Conveyor belt example (demo_MBS_conveyor.cpp) 
  Demonstration of the conveyor belt primitive.
// =============================================================================
// PROJECT CHRONO - http://projectchrono.org
//
// Copyright (c) 2014 projectchrono.org
// All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can be found
// in the LICENSE file at the top level of the distribution and at
// http://projectchrono.org/license-chrono.txt.
//
// =============================================================================
// Authors: Alessandro Tasora
// =============================================================================
//
// Demonstration of the conveyor belt primitive.
// For more advanced features regarding feeding devices, look at demo_IRR_feeder.cpp
//
// =============================================================================
#include "chrono/physics/ChSystemNSC.h"
#include "chrono/physics/ChBodyEasy.h"
#include "chrono/physics/ChConveyor.h"
#include "chrono/core/ChRealtimeStep.h"
#include "chrono/core/ChRandom.h"
#include "chrono_irrlicht/ChVisualSystemIrrlicht.h"
// Use the namespaces of Chrono
using namespace chrono;
using namespace chrono::irrlicht;
// Use the main namespaces of Irrlicht
using namespace irr;
using namespace irr::core;
using namespace irr::scene;
using namespace irr::video;
using namespace irr::io;
using namespace irr::gui;
// Static values valid through the entire program (bad
// programming practice, but enough for quick tests)
double STATIC_flow = 100;
double STATIC_speed = 2;
std::vector<std::shared_ptr<ChBody> > particlelist;
// Define a MyEventReceiver class which will be used to manage input
// from the GUI graphical user interface
class MyEventReceiver : public IEventReceiver {
  public:
    MyEventReceiver(ChVisualSystemIrrlicht& vsys) : vis(vsys), paused(false) {
        // ..add a GUI slider to control particles flow
        scrollbar_flow = vis.GetGUIEnvironment()->addScrollBar(true, rect<s32>(510, 85, 650, 100), 0, 101);
        scrollbar_flow->setMax(300);
        scrollbar_flow->setPos(150);
        text_flow = vis.GetGUIEnvironment()->addStaticText(L"Flow [particles/s]", rect<s32>(650, 85, 750, 100), false);
        // ..add GUI slider to control the speed
        scrollbar_speed = vis.GetGUIEnvironment()->addScrollBar(true, rect<s32>(510, 125, 650, 140), 0, 102);
        scrollbar_speed->setMax(100);
        scrollbar_speed->setPos(100);
        text_speed =
            vis.GetGUIEnvironment()->addStaticText(L"Conveyor speed [m/s]:", rect<s32>(650, 125, 750, 140), false);
    }
    bool OnEvent(const SEvent& event) {
        // check if user moved the sliders with mouse..
        if (event.EventType == EET_GUI_EVENT) {
            s32 id = event.GUIEvent.Caller->getID();
            switch (event.GUIEvent.EventType) {
                case EGET_SCROLL_BAR_CHANGED:
                    if (id == 101)  // id of 'flow' slider..
                    {
                        s32 pos = ((IGUIScrollBar*)event.GUIEvent.Caller)->getPos();
                        STATIC_flow = (double)pos;
                    }
                    if (id == 102)  // id of 'speed' slider..
                    {
                        s32 pos = ((IGUIScrollBar*)event.GUIEvent.Caller)->getPos();
                        STATIC_speed = (((double)pos) / 100) * 2;
                    }
                    break;
                default:
                    break;
            }
        }
        if (event.EventType == irr::EET_KEY_INPUT_EVENT && !event.KeyInput.PressedDown) {
            switch (event.KeyInput.Key) {
                case irr::KEY_SPACE:
                    paused = !paused;
                    return true;
                default:
                    break;
            }
        }
        return false;
    }
    bool paused;
  private:
    ChVisualSystemIrrlicht& vis;
    IGUIScrollBar* scrollbar_flow;
    IGUIStaticText* text_flow;
    IGUIScrollBar* scrollbar_speed;
    IGUIStaticText* text_speed;
};
// Function that creates debris that fall on the conveyor belt, to be called at each dt.
// In this example, all debris particles share the same contact material.
void create_debris(ChVisualSystemIrrlicht& vis, ChSystem& sys, double dt, double particles_second) {
    double xnozzlesize = 0.2;
    double znozzlesize = 0.56;
    double ynozzle = 0.2;
    double box_fraction = 0.3;  // 30% cubes
    double cyl_fraction = 0.4;  // 40% cylinders
    double sphrad = 0.013;
    double exact_particles_dt = dt * particles_second;
    double particles_dt = floor(exact_particles_dt);
    double remaind = exact_particles_dt - particles_dt;
    if (remaind > ChRandom::Get())
        particles_dt += 1;
    auto sphere_mat = chrono_types::make_shared<ChContactMaterialNSC>();
    sphere_mat->SetFriction(0.2f);
    sphere_mat->SetRestitution(0.8f);
    auto box_mat = chrono_types::make_shared<ChContactMaterialNSC>();
    box_mat->SetFriction(0.4f);
    auto cyl_mat = chrono_types::make_shared<ChContactMaterialNSC>();
    cyl_mat->SetFriction(0.2f);
    for (int i = 0; i < particles_dt; i++) {
        double rand_fract = ChRandom::Get();
        if (rand_fract < box_fraction) {
            auto rigidBody = chrono_types::make_shared<ChBodyEasySphere>(sphrad,       // size
                                                                         1000,         // density
                                                                         true,         // visualization?
                                                                         true,         // collision?
                                                                         sphere_mat);  // contact material
            rigidBody->SetPos(ChVector3d(-0.5 * xnozzlesize + ChRandom::Get() * xnozzlesize, ynozzle + i * 0.005,
                                         -0.5 * znozzlesize + ChRandom::Get() * znozzlesize));
            rigidBody->GetVisualShape(0)->SetTexture(GetChronoDataFile("textures/bluewhite.png"));
            sys.Add(rigidBody);
            vis.BindItem(rigidBody);
            sys.GetCollisionSystem()->BindItem(rigidBody);
            particlelist.push_back(rigidBody);
        }
        if ((rand_fract > box_fraction) && (rand_fract < box_fraction + cyl_fraction)) {
            double xscale = 1.3 * (1 - 0.4 * ChRandom::Get());  // for oddly-shaped boxes..
            double yscale = 1.3 * (1 - 0.4 * ChRandom::Get());
            double zscale = 1.3 * (1 - 0.4 * ChRandom::Get());
            auto rigidBody =
                chrono_types::make_shared<ChBodyEasyBox>(sphrad * 2 * xscale, sphrad * 2 * yscale, sphrad * 2 * zscale,
                                                         1000,      // density
                                                         true,      // visualization?
                                                         true,      // collision?
                                                         box_mat);  // contact material
            rigidBody->SetPos(ChVector3d(-0.5 * xnozzlesize + ChRandom::Get() * xnozzlesize, ynozzle + i * 0.005,
                                         -0.5 * znozzlesize + ChRandom::Get() * znozzlesize));
            rigidBody->GetVisualShape(0)->SetTexture(GetChronoDataFile("textures/cubetexture_bluewhite.png"));
            sys.Add(rigidBody);
            vis.BindItem(rigidBody);
            sys.GetCollisionSystem()->BindItem(rigidBody);
            particlelist.push_back(rigidBody);
        }
        if (rand_fract > box_fraction + cyl_fraction) {
                                                                           sphrad, sphrad * 2,  // rad, height
                                                                           1000,                // density
                                                                           true,                // visualization?
                                                                           true,                // collision?
                                                                           cyl_mat);            // contact material
            rigidBody->SetPos(ChVector3d(-0.5 * xnozzlesize + ChRandom::Get() * xnozzlesize, ynozzle + i * 0.005,
                                         -0.5 * znozzlesize + ChRandom::Get() * znozzlesize));
            rigidBody->GetVisualShape(0)->SetTexture(GetChronoDataFile("textures/pinkwhite.png"));
            sys.Add(rigidBody);
            vis.BindItem(rigidBody);
            sys.GetCollisionSystem()->BindItem(rigidBody);
            particlelist.push_back(rigidBody);
        }
    }
}
// Function that deletes old debris (to avoid infinite creation that fills memory)
    while (particlelist.size() > nmaxparticles) {
        sys.Remove(particlelist[0]);               // remove from physical simulation
        particlelist.erase(particlelist.begin());  // remove also from our particle list (will also automatically delete
                                                   // object thank to shared pointer)
    }
}
int main(int argc, char* argv[]) {
    std::cout << "Copyright (c) 2017 projectchrono.org\nChrono version: " << CHRONO_VERSION << std::endl;
    // Create a Chrono physical system
    ChSystemNSC sys;
    // Set small collision envelopes for objects that will be created from now on
    // Create two conveyor fences
    auto fence_mat = chrono_types::make_shared<ChContactMaterialNSC>();
    fence_mat->SetFriction(0.1f);
    auto fence1 = chrono_types::make_shared<ChBodyEasyBox>(2, 0.11, 0.04, 1000, true, true, fence_mat);
    sys.Add(fence1);
    fence1->SetPos(ChVector3d(0, 0, -0.325));
    fence1->SetFixed(true);
    auto fence2 = chrono_types::make_shared<ChBodyEasyBox>(2, 0.11, 0.04, 1000, true, true, fence_mat);
    sys.Add(fence2);
    fence2->SetPos(ChVector3d(0, 0, 0.325));
    fence2->SetFixed(true);
    // Create the conveyor belt (this is a pure Chrono object,
    // because an Irrlicht 'SceneNode' wrapper is not yet available, so it is invisible - no 3D preview)
    auto conveyor_mat = chrono_types::make_shared<ChContactMaterialNSC>();
    conveyor_mat->SetFriction(0.35f);
    auto conveyor = chrono_types::make_shared<ChConveyor>(2, 0.05, 0.6);
    conveyor->SetFixed(true);
    conveyor->SetMaterialSurface(conveyor_mat);
    conveyor->SetConveyorSpeed(STATIC_speed);
    conveyor->SetPos(ChVector3d(0, 0, 0));
    sys.Add(conveyor);
    // Create the Irrlicht visualization system
    auto vis = chrono_types::make_shared<ChVisualSystemIrrlicht>();
    vis->AttachSystem(&sys);
    vis->SetWindowSize(800, 600);
    vis->SetWindowTitle("Conveyor belt");
    vis->Initialize();
    vis->AddLogo();
    vis->AddSkyBox();
    vis->AddTypicalLights();
    // Add the custom event receiver to the default interface
    MyEventReceiver receiver(*vis);
    vis->AddUserEventReceiver(&receiver);
    // Simulation loop
    ChRealtimeStepTimer realtime_timer;
    double timestep = 0.005;
    while (vis->Run()) {
        vis->BeginScene();
        vis->Render();
        vis->EndScene();
        sys.DoStepDynamics(timestep);
        if (!receiver.paused) {
            // Continuosly create debris that fall on the conveyor belt
            create_debris(*vis, sys, timestep, STATIC_flow);
            // Limit the max number of debris particles on the scene, deleting the oldest ones, for performance
            purge_debris(sys, 300);
            // Maybe the user played with the slider and changed STATIC_speed...
            conveyor->SetConveyorSpeed(STATIC_speed);
        }
        realtime_timer.Spin(timestep);
    }
    return 0;
}
void AddTypicalLights()
Simple shortcut to set two point lights in the scene.
Definition: ChVisualSystemIrrlicht.cpp:368
std::string GetChronoDataFile(const std::string &filename)
Get the full path to the specified filename, given relative to the Chrono data directory (thread safe...
Definition: ChDataPath.cpp:37
void Add(std::shared_ptr< ChPhysicsItem > item)
Attach an arbitrary ChPhysicsItem (e.g.
Definition: ChSystem.cpp:214
virtual void Render() override
Draw all 3D shapes and GUI elements at the current frame.
Definition: ChVisualSystemIrrlicht.cpp:594
virtual void Initialize() override
Initialize the visualization system.
Definition: ChVisualSystemIrrlicht.cpp:186
void AddSkyBox(const std::string &texture_dir=GetChronoDataFile("skybox/"))
Add a sky box in a 3D scene.
Definition: ChVisualSystemIrrlicht.cpp:381
void Remove(std::shared_ptr< ChPhysicsItem > item)
Remove arbitrary ChPhysicsItem that was added to the underlying assembly.
Definition: ChSystem.cpp:238
std::shared_ptr< ChCollisionSystem > GetCollisionSystem() const
Access the underlying collision system.
Definition: ChSystem.h:113
Class for a timer which attempts to enforce soft real-time.
Definition: ChRealtimeStep.h:25
void Spin(double step)
Call this function INSIDE the simulation loop, just ONCE per loop (preferably as the last call in the...
Definition: ChRealtimeStep.h:34
virtual void EndScene() override
End the scene draw at the end of each animation frame.
Definition: ChVisualSystemIrrlicht.cpp:584
virtual void BeginScene() override
Perform any necessary operations at the beginning of each rendering frame.
Definition: ChVisualSystemIrrlicht.cpp:567
virtual int AddCamera(const ChVector3d &pos, ChVector3d targ=VNULL) override
Add a camera in an Irrlicht 3D scene.
Definition: ChVisualSystemIrrlicht.cpp:295
void AddUserEventReceiver(irr::IEventReceiver *receiver)
Attach a custom event receiver to the application.
Definition: ChVisualSystemIrrlicht.cpp:462
static void SetDefaultSuggestedMargin(double margin)
Set the default margin (inward penetration).
Definition: ChCollisionModel.cpp:90
int DoStepDynamics(double step_size)
Advance the dynamics simulation by a single time step of given length.
Definition: ChSystem.cpp:1651
Bullet-based collision detection system.
ChVector3< double > ChVector3d
Alias for double-precision vectors.
Definition: ChVector3.h:287
void SetWindowTitle(const std::string &win_title)
Set the windoiw title (default "").
Definition: ChVisualSystemIrrlicht.cpp:143
y direction of a reference frame
virtual void AttachSystem(ChSystem *sys) override
Attach another Chrono system to the run-time visualization system.
Definition: ChVisualSystemIrrlicht.cpp:170
virtual bool Run() override
Run the Irrlicht device.
Definition: ChVisualSystemIrrlicht.cpp:248
virtual void BindItem(std::shared_ptr< ChPhysicsItem > item) override
Process the visual assets for the spcified physics item.
Definition: ChVisualSystemIrrlicht.cpp:644
virtual void SetCollisionSystemType(ChCollisionSystem::Type type)
Set the collision detection system used by this Chrono system to the specified type.
Definition: ChSystem.cpp:342
Class for a physical system in which contact is modeled using a non-smooth (complementarity-based) me...
Definition: ChSystemNSC.h:29
void AddLogo(const std::string &logo_filename=GetChronoDataFile("logo_chrono_alpha.png"))
Add a logo in a 3D scene.
Definition: ChVisualSystemIrrlicht.cpp:360
static void SetDefaultSuggestedEnvelope(double envelope)
Set the default envelope value.
Definition: ChCollisionModel.cpp:86
void SetWindowSize(unsigned int width, unsigned int height)
Set the window size (default 640x480).
Definition: ChVisualSystemIrrlicht.cpp:139
Irrlicht-based Chrono run-time visualization system.
Definition: ChVisualSystemIrrlicht.h:55
