int main(int argc, char* argv[]) {
    GetLog() << "Copyright (c) 2017 projectchrono.org\nChrono version: " << CHRONO_VERSION << "\n\n";

    // Create a ChronoENGINE physical system
    ChSystemNSC mphysicalSystem;

    // Create the Irrlicht visualization (open the Irrlicht device,
    // bind a simple user interface, etc. etc.)
    ChIrrApp application(&mphysicalSystem, L"Conveyor belt", core::dimension2d<u32>(800, 600), false);

    // Easy shortcuts to add camera, lights, logo and sky in Irrlicht scene:
    ChIrrWizard::add_typical_Logo(application.GetDevice());
    ChIrrWizard::add_typical_Sky(application.GetDevice());
    ChIrrWizard::add_typical_Lights(application.GetDevice());
    ChIrrWizard::add_typical_Camera(application.GetDevice(), core::vector3df((f32)1.5, (f32)0.4, -1),
                                    core::vector3df((f32)0.5, 0, 0));

    // This is for GUI tweaking of system parameters..
    MyEventReceiver receiver(&application);
    // note how to add the custom event receiver to the default interface:
    application.SetUserEventReceiver(&receiver);

    // Set small collision envelopes for objects that will be created from now on..
    ChCollisionModel::SetDefaultSuggestedEnvelope(0.002);
    ChCollisionModel::SetDefaultSuggestedMargin(0.002);

    // Create two conveyor fences
   
    auto mfence1 = std::make_shared<ChBodyEasyBox>(2, 0.11, 0.04, 1000, true, true);
    mphysicalSystem.Add(mfence1);
    mfence1->SetPos(ChVector<>(0, 0, -0.325));
    mfence1->SetBodyFixed(true);
    mfence1->GetMaterialSurfaceNSC()->SetFriction(0.1f);
    
    auto mfence2 = std::make_shared<ChBodyEasyBox>(2, 0.11, 0.04, 1000, true, true);
    mphysicalSystem.Add(mfence2);
    mfence2->SetPos(ChVector<>(0, 0,  0.325));
    mfence2->SetBodyFixed(true);
    mfence2->GetMaterialSurfaceNSC()->SetFriction(0.1f);


    // Create the conveyor belt (this is a pure Chrono::Engine object,
    // because an Irrlicht 'SceneNode' wrapper is not yet available, so it is invisible - no 3D preview)

    auto mconveyor = std::make_shared<ChConveyor>(2, 0.05, 0.6);
    mconveyor->SetBodyFixed(true);
    mconveyor->GetMaterialSurfaceNSC()->SetFriction(0.35f);
    mconveyor->SetConveyorSpeed(STATIC_speed);
    mconveyor->SetPos(ChVector<>(0, 0, 0));

    mphysicalSystem.Add(mconveyor);



    // Use this function for adding a ChIrrNodeAsset to all items
    // Otherwise use application.AssetBind(myitem); on a per-item basis.
    application.AssetBindAll();

    // Use this function for 'converting' assets into Irrlicht meshes
    application.AssetUpdateAll();


    //
    // THE SOFT-REAL-TIME CYCLE
    //

    application.SetStepManage(true);
    application.SetTimestep(0.005);

    while (application.GetDevice()->run()) {
        application.BeginScene(true, true, SColor(255, 140, 161, 192));

        application.DrawAll();

        application.DoStep();

        if (!application.GetPaused()) {
            // Continuosly create debris that fall on the conveyor belt
            create_debris(application, application.GetTimestep(), STATIC_flow);

            // Limit the max number of debris particles on the scene, deleting the oldest ones, for performance
            purge_debris(application, 300);

            // Maybe the user played with the slider and changed STATIC_speed...
            mconveyor->SetConveyorSpeed(STATIC_speed);
        }

        application.EndScene();
    }

    return 0;
}
void create_some_falling_items(ChSystemNSC& mphysicalSystem) {
    // From now on, all created collision models will have a large outward envelope (needed
    // to allow some compliance with the plastic deformation of cohesive bounds
    ChCollisionModel::SetDefaultSuggestedEnvelope(0.3);

    for (int bi = 0; bi < 400; bi++) {
        // Create a bunch of ChronoENGINE rigid bodies which will fall..
        auto mrigidBody = std::make_shared<ChBodyEasySphere>(0.81,   // radius
                                                             1000,   // density
                                                             true,   // collide enable?
                                                             true);  // visualization?
        mrigidBody->SetPos(ChVector<>(-5 + ChRandom() * 10, 4 + bi * 0.05, -5 + ChRandom() * 10));
        mrigidBody->GetMaterialSurfaceNSC()->SetFriction(0.3f);

        mphysicalSystem.Add(mrigidBody);

        // optional, attach a texture for better visualization
        auto mtexture = std::make_shared<ChTexture>();
        mtexture->SetTextureFilename(GetChronoDataFile("rock.jpg"));
        mrigidBody->AddAsset(mtexture);
    }

    // Create the five walls of the rectangular container, using
    // fixed rigid bodies of 'box' type:

    auto floorBody = std::make_shared<ChBodyEasyBox>(20, 1, 20,  // x,y,z size
                                                     1000,       // density
                                                     true,       // collide enable?
                                                     true);      // visualization?
    floorBody->SetPos(ChVector<>(0, -5, 0));
    floorBody->SetBodyFixed(true);

    mphysicalSystem.Add(floorBody);

    auto wallBody1 = std::make_shared<ChBodyEasyBox>(1, 10, 20.99,  // x,y,z size
                                                     1000,          // density
                                                     true,          // collide enable?
                                                     true);         // visualization?
    wallBody1->SetPos(ChVector<>(-10, 0, 0));
    wallBody1->SetBodyFixed(true);

    mphysicalSystem.Add(wallBody1);

    auto wallBody2 = std::make_shared<ChBodyEasyBox>(1, 10, 20.99,  // x,y,z size
                                                     1000,          // density
                                                     true,          // collide enable?
                                                     true);         // visualization?
    wallBody2->SetPos(ChVector<>(10, 0, 0));
    wallBody2->SetBodyFixed(true);

    mphysicalSystem.Add(wallBody2);

    auto wallBody3 = std::make_shared<ChBodyEasyBox>(20.99, 10, 1,  // x,y,z size
                                                     1000,          // density
                                                     true,          // collide enable?
                                                     true);         // visualization?
    wallBody3->SetPos(ChVector<>(0, 0, -10));
    wallBody3->SetBodyFixed(true);

    mphysicalSystem.Add(wallBody3);

    auto wallBody4 = std::make_shared<ChBodyEasyBox>(20.99, 10, 1,  // x,y,z size
                                                     1000,          // density
                                                     true,          // collide enable?
                                                     true);         // visualization?
    wallBody4->SetPos(ChVector<>(0, 0, 10));
    wallBody4->SetBodyFixed(true);

    mphysicalSystem.Add(wallBody4);

    // optional, attach  textures for better visualization
    auto mtexturewall = std::make_shared<ChTexture>();
    mtexturewall->SetTextureFilename(GetChronoDataFile("concrete.jpg"));
    wallBody1->AddAsset(mtexturewall);  // note: most assets can be shared
    wallBody2->AddAsset(mtexturewall);
    wallBody3->AddAsset(mtexturewall);
    wallBody4->AddAsset(mtexturewall);
    floorBody->AddAsset(mtexturewall);

    // Add the rotating mixer
    auto rotatingBody = std::make_shared<ChBodyEasyBox>(10, 5, 1,  // x,y,z size
                                                        4000,      // density
                                                        true,      // collide enable?
                                                        true);     // visualization?
    rotatingBody->SetPos(ChVector<>(0, -1.6, 0));
    rotatingBody->GetMaterialSurfaceNSC()->SetFriction(0.4f);

    mphysicalSystem.Add(rotatingBody);

    // .. an engine between mixer and truss
    auto my_motor = std::make_shared<ChLinkEngine>();
    my_motor->Initialize(rotatingBody, floorBody, ChCoordsys<>(ChVector<>(0, 0, 0), Q_from_AngAxis(CH_C_PI_2, VECT_X)));
    my_motor->Set_eng_mode(ChLinkEngine::ENG_MODE_SPEED);
    if (auto mfun = std::dynamic_pointer_cast<ChFunction_Const>(my_motor->Get_spe_funct()))
        mfun->Set_yconst(CH_C_PI / 2.0);  // speed w=90°/s
    mphysicalSystem.AddLink(my_motor);
}
int main(int argc, char* argv[]) {
    GetLog() << "Copyright (c) 2017 projectchrono.org\nChrono version: " << CHRONO_VERSION << "\n\n";

    // Create a ChronoENGINE physical system
    ChSystemNSC mphysicalSystem;

    // Create the Irrlicht visualization (open the Irrlicht device,
    // bind a simple user interface, etc. etc.)
    ChIrrApp application(&mphysicalSystem, L"Gears and pulleys", core::dimension2d<u32>(800, 600), false);

    // Easy shortcuts to add camera, lights, logo and sky in Irrlicht scene:
    ChIrrWizard::add_typical_Logo(application.GetDevice());
    ChIrrWizard::add_typical_Sky(application.GetDevice());
    ChIrrWizard::add_typical_Lights(application.GetDevice());
    ChIrrWizard::add_typical_Camera(application.GetDevice(), core::vector3df(12, 15, -20));

    // Create all the rigid bodies.

    double radA = 2;
    double radB = 4;

    // ...the truss
    auto mbody_truss = std::make_shared<ChBodyEasyBox>(20, 10, 2, 1000, false, true);
    mphysicalSystem.Add(mbody_truss);
    mbody_truss->SetBodyFixed(true);
    mbody_truss->SetPos(ChVector<>(0, 0, 3));

    // ...a texture asset that will be shared among the four wheels
    auto cylinder_texture = std::make_shared<ChTexture>(GetChronoDataFile("pinkwhite.png"));

    // ...the rotating bar support for the two epicycloidal wheels
    auto mbody_train = std::make_shared<ChBodyEasyBox>(8, 1.5, 1.0, 1000, false, true);
    mphysicalSystem.Add(mbody_train);
    mbody_train->SetPos(ChVector<>(3, 0, 0));

    // ...which must rotate respect to truss along Z axis, in 0,0,0,
    auto link_revoluteTT = std::make_shared<ChLinkLockRevolute>();
    link_revoluteTT->Initialize(mbody_truss, mbody_train,
                                ChCoordsys<>(ChVector<>(0, 0, 0), QUNIT));
    mphysicalSystem.AddLink(link_revoluteTT);

    // ...the first gear
    auto mbody_gearA = std::make_shared<ChBodyEasyCylinder>(radA, 0.5, 1000, false, true);
    mphysicalSystem.Add(mbody_gearA);
    mbody_gearA->SetPos(ChVector<>(0, 0, -1));
    mbody_gearA->SetRot(Q_from_AngAxis(CH_C_PI / 2, VECT_X));
    mbody_gearA->AddAsset(cylinder_texture);
    // for aesthetic reasons, also add a thin cylinder only as a visualization:
    auto mshaft_shape = std::make_shared<ChCylinderShape>();
    mshaft_shape->GetCylinderGeometry().p1 = ChVector<>(0,-3,0);
    mshaft_shape->GetCylinderGeometry().p2 = ChVector<>(0, 10,0);
    mshaft_shape->GetCylinderGeometry().rad = radA*0.4;
    mbody_gearA->AddAsset(mshaft_shape);

    // ...impose rotation between the first gear and the fixed truss
    auto link_engine = std::make_shared<ChLinkEngine>();
    link_engine->Initialize(mbody_gearA, mbody_truss, ChCoordsys<>(ChVector<>(0, 0, 0), QUNIT));
    link_engine->Set_shaft_mode(ChLinkEngine::ENG_SHAFT_LOCK);  // also works as revolute support
    link_engine->Set_eng_mode(ChLinkEngine::ENG_MODE_SPEED);
    if (auto mfun = std::dynamic_pointer_cast<ChFunction_Const>(link_engine->Get_spe_funct()))
        mfun->Set_yconst(6);  // rad/s  angular speed
    mphysicalSystem.AddLink(link_engine);

    // ...the second gear
    double interaxis12 = radA + radB;
    auto mbody_gearB = std::make_shared<ChBodyEasyCylinder>(radB, 0.4, 1000, false, true);
    mphysicalSystem.Add(mbody_gearB);
    mbody_gearB->SetPos(ChVector<>(interaxis12, 0, -1));
    mbody_gearB->SetRot(Q_from_AngAxis(CH_C_PI / 2, VECT_X));
    mbody_gearB->AddAsset(cylinder_texture);

    // ... the second gear is fixed to the rotating bar
    auto link_revolute = std::make_shared<ChLinkLockRevolute>();
    link_revolute->Initialize(mbody_gearB, mbody_train,
                              ChCoordsys<>(ChVector<>(interaxis12, 0, 0), QUNIT));
    mphysicalSystem.AddLink(link_revolute);

    // ...the gear constraint between the two wheels A and B.
    //    As transmission ratio (=speed of wheel B / speed of wheel A) to enter in  Set_tau(), we
    //    could use whatever positive value we want: the ChLinkGear will compute the two radii of the
    //    wheels for its 'hidden' computations, given the distance between the two axes. However, since
    //    we already build two '3D cylinders' bodies -just for visualization reasons!- with radA and radB,
    //    we must enter Set_tau(radA/radB).
    //    Also, note that the initial position of the constraint has no importance (simply use CSYSNORM),
    //    but we must set where the two axes are placed in the local coordinates of the two wheels, so
    //    we use Set_local_shaft1() and pass some local ChFrame. Note that, since the Z axis of that frame
    //    will be considered the axis of the wheel, we must rotate the frame 90° with Q_from_AngAxis(), because
    //    we created the wheel with ChBodyEasyCylinder() which created a cylinder with Y as axis.
    auto link_gearAB = std::make_shared<ChLinkGear>();
    link_gearAB->Initialize(mbody_gearA, mbody_gearB, CSYSNORM);
    link_gearAB->Set_local_shaft1(ChFrame<>(VNULL, chrono::Q_from_AngAxis(-CH_C_PI / 2, VECT_X)));
    link_gearAB->Set_local_shaft2(ChFrame<>(VNULL, chrono::Q_from_AngAxis(-CH_C_PI / 2, VECT_X)));
    link_gearAB->Set_tau(radA / radB);
    link_gearAB->Set_checkphase(true);
    mphysicalSystem.AddLink(link_gearAB);

    // ...the gear constraint between the second wheel B and a large wheel C with inner teeth, that
    //    does not necessarily need to be created as a new body because it is the 'fixed' part of the
    //    epicycloidal reducer, so, as wheel C, we will simply use the ground object 'mbody_truss'.
    double radC = 2 * radB + radA;
    auto link_gearBC = std::make_shared<ChLinkGear>();
    link_gearBC->Initialize(mbody_gearB, mbody_truss, CSYSNORM);
    link_gearBC->Set_local_shaft1(ChFrame<>(VNULL, chrono::Q_from_AngAxis(-CH_C_PI / 2, VECT_X)));
    link_gearBC->Set_local_shaft2(ChFrame<>(ChVector<>(0, 0, -4), QUNIT));
    link_gearBC->Set_tau(radB / radC);
    link_gearBC->Set_epicyclic(true);  // <-- this means: use a wheel with internal teeth!
    mphysicalSystem.AddLink(link_gearBC);

    // ...the bevel gear at the side,
    double radD = 5;
    auto mbody_gearD = std::make_shared<ChBodyEasyCylinder>(radD, 0.8, 1000, false, true);
    mphysicalSystem.Add(mbody_gearD);
    mbody_gearD->SetPos(ChVector<>(-10, 0, -9));
    mbody_gearD->SetRot(Q_from_AngAxis(CH_C_PI / 2, VECT_Z));
    mbody_gearD->AddAsset(cylinder_texture);

    // ... it is fixed to the truss using a revolute joint with horizontal axis (must rotate
    //     default ChLink creation coordys 90° on the Y vertical, since the revolute axis is the Z axis).
    auto link_revoluteD = std::make_shared<ChLinkLockRevolute>();
    link_revoluteD->Initialize(mbody_gearD, mbody_truss,
                               ChCoordsys<>(ChVector<>(-10, 0, -9), Q_from_AngAxis(CH_C_PI / 2, VECT_Y)));
    mphysicalSystem.AddLink(link_revoluteD);

    // ... Let's make a 1:1 gear between wheel A and wheel D as a bevel gear: chrono::engine does not require
    //     special info for this case -the position of the two shafts and the transmission ratio are enough-
    auto link_gearAD = std::make_shared<ChLinkGear>();
    link_gearAD->Initialize(mbody_gearA, mbody_gearD, CSYSNORM);
    link_gearAD->Set_local_shaft1(ChFrame<>(ChVector<>(0, -7, 0), chrono::Q_from_AngAxis(-CH_C_PI / 2, VECT_X)));
    link_gearAD->Set_local_shaft2(ChFrame<>(ChVector<>(0, -7, 0), chrono::Q_from_AngAxis(-CH_C_PI / 2, VECT_X)));
    link_gearAD->Set_tau(1);
    mphysicalSystem.AddLink(link_gearAD);

    // ...the pulley at the side,
    double radE = 2;
    auto mbody_pulleyE = std::make_shared<ChBodyEasyCylinder>(radE, 0.8, 1000, false, true);
    mphysicalSystem.Add(mbody_pulleyE);
    mbody_pulleyE->SetPos(ChVector<>(-10, -11, -9));
    mbody_pulleyE->SetRot(Q_from_AngAxis(CH_C_PI / 2, VECT_Z));
    mbody_pulleyE->AddAsset(cylinder_texture);

    // ... it is fixed to the truss using a revolute joint with horizontal axis (must rotate
    //     default ChLink creation coordys 90° on the Y vertical, since the revolute axis is the Z axis).
    auto link_revoluteE = std::make_shared<ChLinkLockRevolute>();
    link_revoluteE->Initialize(mbody_pulleyE, mbody_truss,
                               ChCoordsys<>(ChVector<>(-10, -11, -9), Q_from_AngAxis(CH_C_PI / 2, VECT_Y)));
    mphysicalSystem.AddLink(link_revoluteE);

    // ... Let's make a synchro belt constraint between pulley D and pulley E. The user must be
    //     sure that the two shafts are parallel in absolute space. Also, interaxial distance should not change.
    auto link_pulleyDE = std::make_shared<ChLinkPulley>();
    link_pulleyDE->Initialize(mbody_gearD, mbody_pulleyE, CSYSNORM);
    link_pulleyDE->Set_local_shaft1(ChFrame<>(VNULL, chrono::Q_from_AngAxis(-CH_C_PI / 2, VECT_X)));
    link_pulleyDE->Set_local_shaft2(ChFrame<>(VNULL, chrono::Q_from_AngAxis(-CH_C_PI / 2, VECT_X)));
    link_pulleyDE->Set_r1(radD);
    link_pulleyDE->Set_r2(radE);
    link_pulleyDE->Set_checkphase(true); // synchro belts don't tolerate slipping: this avoids it as numerical errors accumulate.
    mphysicalSystem.AddLink(link_pulleyDE);


    
    // Use this function for adding a ChIrrNodeAsset to all items
    // Otherwise use application.AssetBind(myitem); on a per-item basis.
    application.AssetBindAll();

    // Use this function for 'converting' assets into Irrlicht meshes
    application.AssetUpdateAll();

    // Prepare the physical system for the simulation

    mphysicalSystem.SetTimestepperType(ChTimestepper::Type::EULER_IMPLICIT_PROJECTED);

    //
    // THE SOFT-REAL-TIME CYCLE
    //
    application.SetStepManage(true);
    application.SetTimestep(0.01);
    application.SetTryRealtime(true);

    while (application.GetDevice()->run()) {
        application.BeginScene(true, true, SColor(255, 140, 161, 192));

        application.DrawAll();

        // .. draw also some circle lines representing gears - just for aesthetical reasons

        ChIrrTools::drawCircle(application.GetVideoDriver(), link_gearBC->Get_r2(),
                               (link_gearBC->Get_local_shaft2() >> *link_gearBC->GetBody2()).GetCoord(),
                               video::SColor(255, 255, 0, 0), 50, true);
        ChIrrTools::drawCircle(application.GetVideoDriver(), link_gearAD->Get_r1(),
                               (link_gearAD->Get_local_shaft1() >> *link_gearAD->GetBody1()).GetCoord(),
                               video::SColor(255, 255, 0, 0), 30, true);
        ChIrrTools::drawCircle(application.GetVideoDriver(), link_gearAD->Get_r2(),
                               (link_gearAD->Get_local_shaft2() >> *link_gearAD->GetBody2()).GetCoord(),
                               video::SColor(255, 255, 0, 0), 30, true);

        ChIrrTools::drawCircle(application.GetVideoDriver(), 0.1,
                               ChCoordsys<>(link_gearAB->GetMarker2()->GetAbsCoord().pos, QUNIT));
        ChIrrTools::drawCircle(application.GetVideoDriver(), 0.1,
                               ChCoordsys<>(link_gearAD->GetMarker2()->GetAbsCoord().pos, QUNIT));
        ChIrrTools::drawCircle(application.GetVideoDriver(), 0.1,
                               ChCoordsys<>(link_gearBC->GetMarker2()->GetAbsCoord().pos, QUNIT));

        // ..draw also some segments for a simplified representation of pulley
        ChIrrTools::drawSegment(application.GetVideoDriver(), link_pulleyDE->Get_belt_up1(),
                                link_pulleyDE->Get_belt_up2(), video::SColor(255, 0, 255, 0), true);
        ChIrrTools::drawSegment(application.GetVideoDriver(), link_pulleyDE->Get_belt_low1(),
                                link_pulleyDE->Get_belt_low2(), video::SColor(255, 0, 255, 0), true);

        // ADVANCE THE SIMULATION FOR ONE STEP

        application.DoStep();

        application.EndScene();
    }

    return 0;
}
int main(int argc, char* argv[]) {
    GetLog() << "Copyright (c) 2017 projectchrono.org\nChrono version: " << CHRONO_VERSION << "\n\n";

    // Create the system
    // Set gravitational acceleration to zero
    ChSystemNSC system;
    system.Set_G_acc(ChVector<>(0, 0, 0));

    // Create the ground body
    auto ground = std::make_shared<ChBodyEasyBox>(3, 2, 0.1, 10, false, true);
    system.AddBody(ground);
    ground->SetBodyFixed(true);

    // Create the sliding body
    // Give an initial angular velocity
    auto body = std::make_shared<ChBodyEasyBox>(0.5, 0.5, 0.5, 10, false, true);
    system.AddBody(body);
    body->SetBodyFixed(false);
    body->SetPos(ChVector<>(-1.25, -0.75, 0.1));
    body->SetWvel_loc(ChVector<>(0.1, 0.1, 0.1));

    auto body_col = std::make_shared<ChColorAsset>();
    body_col->SetColor(ChColor(0.6f, 0, 0));
    body->AddAsset(body_col);

    // Create the plane-plane constraint
    // Constrain the sliding body to move and rotate in the x-y plane
    // (i.e. the plane whose normal is the z-axis of the specified coord sys)
    auto plane_plane = std::make_shared<ChLinkLockPlanePlane>();
    plane_plane->Initialize(ground, body, ChCoordsys<>(ChVector<>(-1.25, -0.75, 0), ChQuaternion<>(1, 0, 0, 0)));
    system.AddLink(plane_plane);

    // Create a linear spring (with default spring & damping coefficients)
    auto spring = std::make_shared<ChLinkSpring>();
    spring->Initialize(ground, body, true, ChVector<>(0, 0, 2), ChVector<>(0, 0, 0), false, 1.9);
    system.AddLink(spring);

    // Create the Irrlicht application
    ChIrrApp application(&system, L"ChLinkLockPlanePlane", irr::core::dimension2d<irr::u32>(800, 600), false, true);
    application.AddTypicalLogo();
    application.AddTypicalSky();
    application.AddTypicalLights();
    application.AddTypicalCamera(irr::core::vector3df(3, 0, 3));

    application.AssetBindAll();
    application.AssetUpdateAll();

    // Simulation loop
    application.SetTimestep(0.005);

    while (application.GetDevice()->run()) {
        application.BeginScene();
        application.DrawAll();
        ChIrrTools::drawSpring(application.GetVideoDriver(), 0.05, spring->GetEndPoint1Abs(), spring->GetEndPoint2Abs(),
                               irr::video::SColor(0, 255, 255, 100), 80, 15, true);
        ChIrrTools::drawAllCOGs(system, application.GetVideoDriver(), 2);
        application.EndScene();
        application.DoStep();
    }

    return 0;
}
void create_wall_bodies(ChSystemNSC& mphysicalSystem) {
    // Create a material that will be shared between bricks
    auto mmaterial = std::make_shared<ChMaterialSurfaceNSC>();
    mmaterial->SetFriction(0.4f);
    mmaterial->SetCompliance(0.0000005f);
    mmaterial->SetComplianceT(0.0000005f);
    mmaterial->SetDampingF(0.2f);

    // Create bricks
    for (int ai = 0; ai < 1; ai++)  // N. of walls
    {
        for (int bi = 0; bi < 10; bi++)  // N. of vert. bricks
        {
            for (int ui = 0; ui < 15; ui++)  // N. of hor. bricks
            {
                auto mrigidBody = std::make_shared<ChBodyEasyBox>(3.96, 2, 4,  // x,y,z size
                                                                  100,         // density
                                                                  true,        // collide enable?
                                                                  true);       // visualization?
                mrigidBody->SetPos(ChVector<>(-8 + ui * 4.0 + 2 * (bi % 2), 1.0 + bi * 2.0, ai * 9));
                mrigidBody->SetMaterialSurface(mmaterial);  // use shared surface properties

                mphysicalSystem.Add(mrigidBody);

                // optional, attach a texture for better visualization
                auto mtexture = std::make_shared<ChTexture>();
                mtexture->SetTextureFilename(GetChronoDataFile("cubetexture_borders.png"));
                mrigidBody->AddAsset(mtexture);
            }
        }
    }

    // Create the floor using
    // fixed rigid body of 'box' type:

    auto mrigidFloor = std::make_shared<ChBodyEasyBox>(250, 4, 250,  // x,y,z size
                                                       1000,         // density
                                                       true,         // collide enable?
                                                       true);        // visualization?
    mrigidFloor->SetPos(ChVector<>(0, -2, 0));
    mrigidFloor->SetMaterialSurface(mmaterial);
    mrigidFloor->SetBodyFixed(true);

    mphysicalSystem.Add(mrigidFloor);

    // Create a ball that will collide with wall
    auto mrigidBall = std::make_shared<ChBodyEasySphere>(4,      // radius
                                                         8000,   // density
                                                         true,   // collide enable?
                                                         true);  // visualization?
    mrigidBall->SetPos(ChVector<>(0, -2, 0));
    mrigidBall->SetMaterialSurface(mmaterial);
    mrigidBall->SetPos(ChVector<>(0, 3, -8));
    mrigidBall->SetPos_dt(ChVector<>(0, 0, 16));          // set initial speed
    mrigidBall->GetMaterialSurfaceNSC()->SetFriction(0.4f);  // use own (not shared) matrial properties
    mrigidBall->GetMaterialSurfaceNSC()->SetCompliance(0.0);
    mrigidBall->GetMaterialSurfaceNSC()->SetComplianceT(0.0);
    mrigidBall->GetMaterialSurfaceNSC()->SetDampingF(0.2f);

    mphysicalSystem.Add(mrigidBall);

    // optional, attach a texture for better visualization
    auto mtextureball = std::make_shared<ChTexture>();
    mtextureball->SetTextureFilename(GetChronoDataFile("bluwhite.png"));
    mrigidBall->AddAsset(mtextureball);
}
int main(int argc, char* argv[]) {
    GetLog() << "Copyright (c) 2017 projectchrono.org\nChrono version: " << CHRONO_VERSION << "\n\n";

    // Create a ChronoENGINE physical system
    ChSystemNSC mphysicalSystem;

    // Create the Irrlicht visualization (open the Irrlicht device,
    // bind a simple user interface, etc. etc.)
    ChIrrApp application(&mphysicalSystem, L"Bricks test", core::dimension2d<u32>(800, 600), false, true);

    // Easy shortcuts to add camera, lights, logo and sky in Irrlicht scene:
    ChIrrWizard::add_typical_Logo(application.GetDevice());
    ChIrrWizard::add_typical_Sky(application.GetDevice());
    ChIrrWizard::add_typical_Lights(application.GetDevice(), core::vector3df(70.f, 120.f, -90.f),
                                    core::vector3df(30.f, 80.f, 60.f), 290, 190);
    ChIrrWizard::add_typical_Camera(application.GetDevice(), core::vector3df(-15, 14, -30), core::vector3df(0, 5, 0));

    //
    // HERE YOU POPULATE THE MECHANICAL SYSTEM OF CHRONO...
    //

    // Create all the rigid bodies.
    create_wall_bodies(mphysicalSystem);
    // create_jengatower_bodies (mphysicalSystem);

    // Use this function for adding a ChIrrNodeAsset to all items
    // If you need a finer control on which item really needs a visualization proxy in
    // Irrlicht, just use application.AssetBind(myitem); on a per-item basis.
    application.AssetBindAll();

    // Use this function for 'converting' into Irrlicht meshes the assets
    // into Irrlicht-visualizable meshes
    application.AssetUpdateAll();

    // Prepare the physical system for the simulation

    mphysicalSystem.SetSolverType(ChSolver::Type::SOR_MULTITHREAD);

    //mphysicalSystem.SetUseSleeping(true);

    mphysicalSystem.SetMaxPenetrationRecoverySpeed(1.6);  // used by Anitescu stepper only
    mphysicalSystem.SetMaxItersSolverSpeed(40);
    mphysicalSystem.SetMaxItersSolverStab(20);  // unuseful for Anitescu, only Tasora uses this
    mphysicalSystem.SetSolverWarmStarting(true);
    mphysicalSystem.SetParallelThreadNumber(4);

    //
    // THE SOFT-REAL-TIME CYCLE
    //

    application.SetStepManage(true);
    application.SetTimestep(0.02);

    while (application.GetDevice()->run()) {
        application.BeginScene(true, true, SColor(255, 140, 161, 192));

        ChIrrTools::drawGrid(application.GetVideoDriver(), 5, 5, 20, 20,
                             ChCoordsys<>(ChVector<>(0, 0.04, 0), Q_from_AngAxis(CH_C_PI / 2, VECT_X)),
                             video::SColor(50, 90, 90, 150), true);

        application.DrawAll();

        application.DoStep();

        application.EndScene();
    }

    return 0;
}
void create_jengatower_bodies(ChSystemNSC& mphysicalSystem) {
    // Create a material that will be shared between bricks
    auto mmaterial = std::make_shared<ChMaterialSurfaceNSC>();
    mmaterial->SetFriction(0.4f);
    mmaterial->SetCompliance(0.0000005f);
    mmaterial->SetComplianceT(0.0000005f);
    mmaterial->SetDampingF(0.2f);

    // Create bricks
    for (int bi = 0; bi < 12; bi += 2) {
        auto mrigidBody1 = std::make_shared<ChBodyEasyBox>(2, 2, 14,        // x,y,z size
                                                           100,             // density
                                                           true,            // collide enable?
                                                           true);           // visualization?
        mrigidBody1->SetPos(ChVector<>(-5, 1.0 + bi * 2.0, 0));
        mrigidBody1->SetMaterialSurface(mmaterial);  // use shared surface properties
        mphysicalSystem.Add(mrigidBody1);

        auto mrigidBody2 = std::make_shared<ChBodyEasyBox>(2, 2, 14,  // x,y,z size
                                                           100,       // density
                                                           true,      // collide enable?
                                                           true);     // visualization?
        mrigidBody2->SetPos(ChVector<>(5, 1.0 + bi * 2.0, 0));
        mrigidBody2->SetMaterialSurface(mmaterial);  // use shared surface properties
        mphysicalSystem.Add(mrigidBody2);

        auto mrigidBody3 = std::make_shared<ChBodyEasyBox>(14, 2, 2,  // x,y,z size
                                                           100,       // density
                                                           true,      // collide enable?
                                                           true);     // visualization?
        mrigidBody3->SetPos(ChVector<>(0, 3.0 + bi * 2.0, 5));
        mrigidBody3->SetMaterialSurface(mmaterial);  // use shared surface properties
        mphysicalSystem.Add(mrigidBody3);

        auto mrigidBody4 = std::make_shared<ChBodyEasyBox>(14, 2, 2,  // x,y,z size
                                                           100,       // density
                                                           true,      // collide enable?
                                                           true);     // visualization?
        mrigidBody4->SetPos(ChVector<>(0, 3.0 + bi * 2.0, -5));
        mrigidBody4->SetMaterialSurface(mmaterial);  // use shared surface properties
        mphysicalSystem.Add(mrigidBody4);
    }

    // Create the floor using
    // fixed rigid body of 'box' type:
    auto mrigidFloor = std::make_shared<ChBodyEasyBox>(250, 4, 250,  // x,y,z size
                                                       1000,         // density
                                                       true,         // collide enable?
                                                       true);        // visualization?
    mrigidFloor->SetPos(ChVector<>(0, -2, 0));
    mrigidFloor->SetMaterialSurface(mmaterial);
    mrigidFloor->SetBodyFixed(true);

    mphysicalSystem.Add(mrigidFloor);

    // Create a ball that will collide with tower
    auto mrigidBall = std::make_shared<ChBodyEasySphere>(4,      // radius
                                                         1000,   // density
                                                         true,   // collide enable?
                                                         true);  // visualization?
    mrigidBall->SetMaterialSurface(mmaterial);
    mrigidBall->SetPos(ChVector<>(0, 3, -8));
    mrigidBall->SetPos_dt(ChVector<>(0, 0, 2));           // set initial speed
    mrigidBall->GetMaterialSurfaceNSC()->SetFriction(0.4f);  // use own (not shared) matrial properties
    mrigidBall->GetMaterialSurfaceNSC()->SetCompliance(0.0);
    mrigidBall->GetMaterialSurfaceNSC()->SetComplianceT(0.0);
    mrigidBall->GetMaterialSurfaceNSC()->SetDampingF(0.2f);

    mphysicalSystem.Add(mrigidBall);

    // optional, attach a texture for better visualization
    auto mtextureball = std::make_shared<ChTexture>();
    mtextureball->SetTextureFilename(GetChronoDataFile("bluwhite.png"));
    mrigidBall->AddAsset(mtextureball);
}
int main(int argc, char* argv[]) {
    GetLog() << "Copyright (c) 2017 projectchrono.org\nChrono version: " << CHRONO_VERSION << "\n\n";

    // Create a ChronoENGINE physical system
    ChSystemNSC mphysicalSystem;

    // ** user input
    double wheelMass = 5.0;  // mass of wheel
    double suspMass = 10.0;  // mass of suspended weight

    // Create the Irrlicht visualization (open the Irrlicht device,
    // bind a simple user interface, etc. etc.)
    ChIrrApp application(&mphysicalSystem, L"Soil bin demo", core::dimension2d<u32>(1024, 768), false);
    ChIrrWizard::add_typical_Logo(application.GetDevice());
    ChIrrWizard::add_typical_Sky(application.GetDevice());
    ChIrrWizard::add_typical_Lights(application.GetDevice(), irr::core::vector3df(20., 30., 25.),
                                    irr::core::vector3df(25., 25., -25.), 65.0, 75.);
    ChIrrWizard::add_typical_Camera(application.GetDevice(), core::vector3df(3.5f, 2.5f, -2.4f));

    // ******* SOIL BIN WHEEL
    // Create the wheel
    ChVector<> wheelCMpos = ChVector<>(0, 0.5, 0);
    ChVector<> wheelInertia = ChVector<>(1.0, 1.0, 1.0);
    SoilbinWheel* mwheel = new SoilbinWheel(&mphysicalSystem, wheelCMpos, wheelMass, wheelInertia);

    // ***** TESTING MECHANISM
    // now, create the testing mechanism and attach the wheel to it
    double binWidth = 1.0;
    double binLen = 2.4;
    TestMech* mTestMechanism = new TestMech(&mphysicalSystem, mwheel->wheel, binWidth, binLen, suspMass, 2500., 10.);

    // ***** PARTICLE GENERATOR
    // make a particle generator, that the sceneManager can use to easily dump a bunch of dirt in the bin
    ParticleGenerator* mParticleGen = new ParticleGenerator(&application, &mphysicalSystem, binWidth, binLen);

    // Bind visualization assets.
    application.AssetBindAll();
    application.AssetUpdateAll();

    // ***** Create the User - GUI
    double torqueMax = 50.;
    MyEventReceiver receiver(&application, mwheel, mTestMechanism, mParticleGen, 0.02, 0.02, torqueMax);
    // add a custom event receiver to the default interface:
    application.SetUserEventReceiver(&receiver);

    // Set some integrator settings
    // mphysicalSystem.SetSolverType(ChSolver::Type::APGD);
    mphysicalSystem.SetSolverType(ChSolver::Type::SOR_MULTITHREAD);
    mphysicalSystem.SetMaxItersSolverSpeed(70);
    mphysicalSystem.SetMaxItersSolverStab(15);
    mphysicalSystem.SetParallelThreadNumber(4);

    // Use real-time step of the simulation, OR...
    application.SetStepManage(true);
    application.SetTimestep(0.01);
    application.SetTryRealtime(true);

    while (application.GetDevice()->run()) {
        application.BeginScene(true, true, SColor(255, 140, 161, 192));
        application.DrawAll();

        // draw the custom links
        receiver.drawSprings();
        receiver.drawGrid();

        // output relevant soil, wheel data if the tab is selected
        if (receiver.gad_tab_soil->isVisible())
            receiver.drawSoilOutput();
        if (receiver.gad_tab_wheel->isVisible())
            receiver.drawWheelOutput();
        receiver.drawWheelOutput();

        // apply torque to the wheel
        mTestMechanism->applyTorque();

        application.DoStep();

        if (!application.GetPaused()) {
            // add bodies to the system?
            if (receiver.createParticles()) {
                receiver.genParticles();
            }
        }

        application.EndScene();
    }

    return 0;
}
void create_some_falling_items(ChSystemNSC& mphysicalSystem, ISceneManager* msceneManager, IVideoDriver* driver) {
    for (int bi = 0; bi < 29; bi++) {
        // Create a bunch of ChronoENGINE rigid bodies (spheres and
        // boxes etc.) which will fall..

        auto msphereBody = std::make_shared<ChBodyEasySphere>(1.1,    // radius size
                                                              1000,   // density
                                                              true,   // collide enable?
                                                              true);  // visualization?
        msphereBody->SetPos(ChVector<>(-5 + ChRandom() * 10, 4 + bi * 0.05, -5 + ChRandom() * 10));
        msphereBody->GetMaterialSurfaceNSC()->SetFriction(0.2f);

        mphysicalSystem.Add(msphereBody);

        // optional, attach a texture for better visualization
        auto mtexture = std::make_shared<ChTexture>();
        mtexture->SetTextureFilename(GetChronoDataFile("bluwhite.png"));
        msphereBody->AddAsset(mtexture);

        auto mboxBody = std::make_shared<ChBodyEasyBox>(1.5, 1.5, 1.5,  // x,y,z size
                                                        100,            // density
                                                        true,           // collide enable?
                                                        true);          // visualization?
        mboxBody->SetPos(ChVector<>(-5 + ChRandom() * 10, 4 + bi * 0.05, -5 + ChRandom() * 10));

        mphysicalSystem.Add(mboxBody);

        // optional, attach a texture for better visualization
        auto mtexturebox = std::make_shared<ChTexture>();
        mtexturebox->SetTextureFilename(GetChronoDataFile("cubetexture_bluwhite.png"));
        mboxBody->AddAsset(mtexturebox);

        auto mcylBody = std::make_shared<ChBodyEasyCylinder>(0.75, 0.5,  // radius, height
                                                             100,        // density
                                                             true,       // collide enable?
                                                             true);      // visualization?
        mcylBody->SetPos(ChVector<>(-5 + ChRandom() * 10, 4 + bi * 0.05, -5 + ChRandom() * 10));

        mphysicalSystem.Add(mcylBody);

        // optional, attach a texture for better visualization
        auto mtexturecyl = std::make_shared<ChTexture>();
        mtexturecyl->SetTextureFilename(GetChronoDataFile("pinkwhite.png"));
        mcylBody->AddAsset(mtexturecyl);
    }

    // Create the five walls of the rectangular container, using
    // fixed rigid bodies of 'box' type:

    auto floorBody = std::make_shared<ChBodyEasyBox>(20, 1, 20, 1000, true, true);
    floorBody->SetPos(ChVector<>(0, -5, 0));
    floorBody->SetBodyFixed(true);

    mphysicalSystem.Add(floorBody);

    auto wallBody1 = std::make_shared<ChBodyEasyBox>(1, 10, 20.99, 1000, true, true);
    wallBody1->SetPos(ChVector<>(-10, 0, 0));
    wallBody1->SetBodyFixed(true);

    mphysicalSystem.Add(wallBody1);

    auto wallBody2 = std::make_shared<ChBodyEasyBox>(1, 10, 20.99, 1000, true, true);
    wallBody2->SetPos(ChVector<>(10, 0, 0));
    wallBody2->SetBodyFixed(true);

    mphysicalSystem.Add(wallBody2);

    auto wallBody3 = std::make_shared<ChBodyEasyBox>(20.99, 10, 1, 1000, true, true);
    wallBody3->SetPos(ChVector<>(0, 0, -10));
    wallBody3->SetBodyFixed(true);

    mphysicalSystem.Add(wallBody3);

    auto wallBody4 = std::make_shared<ChBodyEasyBox>(20.99, 10, 1, 1000, true, true);
    wallBody4->SetPos(ChVector<>(0, 0, 10));
    wallBody4->SetBodyFixed(true);

    mphysicalSystem.Add(wallBody4);

    // optional, attach  textures for better visualization
    auto mtexturewall = std::make_shared<ChTexture>();
    mtexturewall->SetTextureFilename(GetChronoDataFile("concrete.jpg"));
    wallBody1->AddAsset(mtexturewall);  // note: most assets can be shared
    wallBody2->AddAsset(mtexturewall);
    wallBody3->AddAsset(mtexturewall);
    wallBody4->AddAsset(mtexturewall);
    floorBody->AddAsset(mtexturewall);

    // Add the rotating mixer
    auto rotatingBody = std::make_shared<ChBodyEasyBox>(10, 5, 1,        // x,y,z size
                                                        4000,            // density
                                                        true,            // collide enable?
                                                        true);           // visualization?
    rotatingBody->SetPos(ChVector<>(0, -1.6, 0));
    rotatingBody->GetMaterialSurfaceNSC()->SetFriction(0.4f);

    mphysicalSystem.Add(rotatingBody);

    // .. a motor between mixer and truss

    auto my_motor = std::make_shared<ChLinkMotorRotationSpeed>();
    my_motor->Initialize(rotatingBody, floorBody, ChFrame<>(ChVector<>(0, 0, 0), Q_from_AngAxis(CH_C_PI_2, VECT_X)));
    auto mfun = std::make_shared<ChFunction_Const>(CH_C_PI / 2.0);  // speed w=90°/s
    my_motor->SetSpeedFunction(mfun);
    mphysicalSystem.AddLink(my_motor);

    /*

    /// NOTE: Instead of creating five separate 'box' bodies to make
    /// the walls of the bowl, you could have used a single body
    /// made of five box shapes, which build a single collision description,
    /// as in the alternative approach:

        // create a plain ChBody (no colliding shape nor visualization mesh is used yet)
    auto mrigidBody = std::make_shared<ChBody>();

        // set the ChBodySceneNode as fixed body, and turn collision ON, otherwise no collide by default
    mrigidBody->SetBodyFixed(true);
    mrigidBody->SetCollide(true);

        // Clear model. The colliding shape description MUST be between  ClearModel() .. BuildModel() pair.
    mrigidBody->GetCollisionModel()->ClearModel();
        // Describe the (invisible) colliding shape by adding five boxes (the walls and floor)
    mrigidBody->GetCollisionModel()->AddBox(20,1,20, ChVector<>(  0,-10,  0));
    mrigidBody->GetCollisionModel()->AddBox(1,40,20, ChVector<>(-11,  0,  0));
    mrigidBody->GetCollisionModel()->AddBox(1,40,20, ChVector<>( 11,  0,  0));
    mrigidBody->GetCollisionModel()->AddBox(20,40,1, ChVector<>(  0,  0,-11));
    mrigidBody->GetCollisionModel()->AddBox(20,40,1, ChVector<>(  0,  0, 11));
        // Complete the description of collision shape.
    mrigidBody->GetCollisionModel()->BuildModel();

        // Attach some visualization shapes if needed:
    auto vshape = std::make_shared<ChBoxShape>();
    vshape->GetBoxGeometry().SetLengths( ChVector<> (20,1,20) );
    vshape->GetBoxGeometry().Pos = ChVector<> (0,-5,0);
    this->AddAsset( vshape );
    // etc. for other 4 box shapes..
    */
}