VR-Vantage 2.4 API Documentation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
The Distributed Simulation Tutorial - Conclusion

Introduction to Project 5

Project 5 in the Distributed Simulation tutorial pulls together what we have learned in earlier projects. Although we won't use threaded connections or VR-Vantage listeners, this project could easily be changed to use them. Instead, we will use a simple VR-Link connection and a detonation callback to receive detonation data interactions. We will also use the pre-existing VR-Vantage agent in order to place a distinct entity into the scene at the coordinates of each detonation interaction received.

Examining the files that make up the project

For this project, all files from Project 2A will be reused. We will also reuse the custom connection class created for Project 3B. All changes, other than filenames, will be made in the DistributedSimulationDriver class files.

As with Project 3A, in the driver header file we define DtDetonationInteraction as an alias for the VR-Link DtDetonationPdu class type. This helps the code to be self-documenting. To remember which objects were added to the scene to later support animation and eventual removal, we add two more type definitions: one to pair a scene object agent with its associated a model agent, and one as an array of such scene object/model object pairs. We then instantiation a list of such pairs as a member of the driver class.

typedef DtDetonationPdu DtDetonationInteraction;

//! Typedefs describing a SceneObject/Model pair and a list of such pairs.
typedef std::pair<DtSceneObjectAgent*, DtModelAgent*> SceneObjectAndModelPair;
typedef std::vector<SceneObjectAndModelPair> SceneObjectAndModelList;

SceneObjectAndModelList mySceneObjectAgentsList;

For the driver definition file, we will need to include the following header files:

The new onStart() function looks as follows:

bool DistributedSimulationDriver::onStart()
{
std::cout << "DistributedSimulationDriver::onStart(): " << std::endl;
init.setPort(3152);
init.setExerciseId(1);
init.setSiteId(2);
init.setApplicationNumber(1);
// VR-Link default buffer is to small for this application; set it to 1 MB.
init.setReceiveBufferSize(0x100000);
DtAgentManagerInterface* simSceneInterface = &myAgentManager;
mySimulation = new DistributedSimulationConnection(*simSceneInterface,
DtSharedSettingsManager::instance(agentManager().de()));
mySimulation->connect(init);
// Add all models to the scene that may have already been encountered
// in the case where a previous onStart() was followed by an onStop().
for (unsigned int i=0; i<mySceneObjectAgentsList.size(); i++)
{
mySceneObjectAgentsList[i].first->addModel(
mySceneObjectAgentsList[i].second, 0);
}
// Add a detonation interaction callback
DtDetonationInteraction::addCallback(mySimulation->exerciseConn(), &processDetonationCb, this);
return mySimulation->connected();
}

Here we have used the same code as for Project 3B in order to instantiate a custom connection object.

DtAgentManagerInterface* simSceneInterface = &myAgentManager;
mySimulation = new DistributedSimulationConnection(*simSceneInterface,
DtSharedSettingsManager::instance(agentManager().de()));
mySimulation->connect(init);

We then run through our list of scene object/model object pairs and populate the scene with them. This list is initially empty, but this is necessary in the case where we wanted to place already encountered objects back in the scene each time we restart the driver.

// Add all models to the scene that may have already been encountered
// in the case where a previous onStart() was followed by an onStop().
for (unsigned int i=0; i<mySceneObjectAgentsList.size(); i++)
{
mySceneObjectAgentsList[i].first->addModel(
mySceneObjectAgentsList[i].second, 0);
}

We then need to add our callback function so that we can receive and respond to detonation interaction data as it comes over our custom connection.

DtDetonationInteraction::addCallback(mySimulation->exerciseConn(), &processDetonationCb, this);

The onStop() function now needs to run through the same list of scene object/model object pairs in order to remove our entities from the scene. We don't delete our objects or clear the list since in our case we will replace these objects in the scene each time we click Start.

bool DistributedSimulationDriver::onStop()
{
// NOTE: breakdown code goes here. Return false on bad status.
std::cout << "DistributedSimulationDriver::onStop(): " << std::endl;
if (mySimulation)
delete mySimulation;
mySimulation = 0;
// Remove all models from the scene
for (unsigned int i=0; i<mySceneObjectAgentsList.size(); i++)
{
mySceneObjectAgentsList[i].first->removeModel(
mySceneObjectAgentsList[i].second);
}
return true;
}

The onTick() function now runs through our object pair list in order to animate each cow image to rotate to the left.

bool DistributedSimulationDriver::onTick()
{
// printout to show whether or not connected at the tick level
bool connState = mySimulation->connected();
if (connState)
{
int numread = mySimulation->exerciseConn()->drainInput();
std::cout << "." << numread;
}
else
std::cout << "x";
// rotate all models to the left.
for (unsigned int i=0; i<mySceneObjectAgentsList.size(); i++)
{
const DtTaitBryan orient(myRotationDegree, 0, 0);
mySceneObjectAgentsList[i].first->setOrientation(0, orient);
myRotationDegree -= 0.005;
if(myRotationDegree < 0.0)
{
myRotationDegree = 360.0;
}
}
return connState;
}

The final change is to add a loop to the destructor so that we can run through our object pair list to remove our entities from the scene and reclaim memory.

DistributedSimulationDriver::~DistributedSimulationDriver(void)
{
// Remove all models from the scene and reclaim memory
for (unsigned int i=0; i<mySceneObjectAgentsList.size(); i++)
{
mySceneObjectAgentsList[i].first->removeModel(
mySceneObjectAgentsList[i].second);
delete mySceneObjectAgentsList[i].first;
delete mySceneObjectAgentsList[i].second;
}
mySceneObjectAgentsList.clear();
}

Testing the plugin

Invoke either the tutorialDistributedSimulation5d.bat or tutorialDistributedSimulation5.sh script file to start the VR-Vantage Stealth application. Follow these instructions to test the plugin:

  1. Choose File > View > Drivers Panel.
  2. Load the Makland terrain.
  3. Navigate through the terrain so that you are looking toward the south from a vantage point north of the peninsula. You should see the water and the peninsula ahead. From this vantage point you should be able to see all of the entities that are added to the scene in response to detonations that occur in VR-Forces.
  4. Select the driver named "DistributedSimulationDriver5".
  5. Click on the Start button.
  6. Start up a VR-Forces application using DIS as the protocol, open the Makland scenario, and then start the scenario. As detonations occur in VR-Forces, you will notice that images of cows start to appear at the same coordinates in the VR-Vantage simulation. Each cow will be rotating to the left.
  7. In Stealth, make sure the same driver is selected in the Drivers Panel, and click the Stop button.
  8. You will notice that the all of the cow images have been removed from the scene.
  9. Continually clicking the Start and Stop button will continue to start the driver (placing all currently detected cow images back into the scene) and stop the driver (removing all currently detected cow images from the scene). Note that any detonations that occur in VR-Forces while the driver is stopped in VR-Vantage will never be detected by the driver. These will never be added as cow nodes to the list of agents, and will therefore never be added to the scene.

[<< Add an Entity Using a Custom Agent]


Project Files

DistributedSimulationDriver5.h

/******************************************************************************
** Copyright (c) 2011 MAK Technologies, Inc.
** All rights reserved.
******************************************************************************/
#pragma once
class DtDetonationPdu;
typedef DtDetonationPdu DtDetonationInteraction;
namespace makVrv
{
class DtSceneObjectAgent;
class DtModelAgent;
namespace tutorialDistributedSimulation5
{
class DistributedSimulationConnection;
class DistributedSimulationDriver : public DtDriver
{
public:
typedef std::pair<DtSceneObjectAgent*, DtModelAgent*> SceneObjectAndModelPair;
typedef std::vector<SceneObjectAndModelPair> SceneObjectAndModelList;
virtual const std::string& className() const;
protected:
virtual bool onStart();
virtual bool onStop();
virtual bool onTick();
static void processDetonationCb(DtDetonationInteraction* inter, void* usr);
virtual void processDetonation(DtDetonationInteraction* inter);
protected:
DistributedSimulationConnection* mySimulation;
SceneObjectAndModelList mySceneObjectAgentsList;
};
}
}

DistributedSimulationDriver5.cxx

/******************************************************************************
** Copyright (c) 2014 MAK Technologies, Inc.
** All rights reserved.
******************************************************************************/
// Compile VR-Link code for DIS protocol
#define DtDIS 1
#include <vrvCore/DtDe.h>
#include <vl/detonationInteraction.h>
#include <vl/exerciseConnInitializer.h>
#include <vl/exerciseConn.h>
#include <iostream>
namespace makVrv
{
namespace tutorialDistributedSimulation5
{
DtAgentManager& agentManager, const std::string& instanceName)
: DtDriver(agentManager, instanceName)
, mySimulation(0)
, myRotationDegree(0)
{
}
DistributedSimulationDriver::~DistributedSimulationDriver(void)
{
// Remove all models from the scene and reclaim memory
for (unsigned int i=0; i<mySceneObjectAgentsList.size(); i++)
{
mySceneObjectAgentsList[i].first->removeModel(
mySceneObjectAgentsList[i].second);
delete mySceneObjectAgentsList[i].first;
delete mySceneObjectAgentsList[i].second;
}
mySceneObjectAgentsList.clear();
}
const std::string& DistributedSimulationDriver::className() const
{
// name must be static, since it's returned by reference
static std::string name("DistributedSimulationDriver");
return name;
}
bool DistributedSimulationDriver::onStart()
{
std::cout << "DistributedSimulationDriver::onStart(): " << std::endl;
init.setPort(3152);
init.setExerciseId(1);
init.setSiteId(2);
init.setApplicationNumber(1);
// VR-Link default buffer is to small for this application; set it to 1 MB.
init.setReceiveBufferSize(0x100000);
DtAgentManagerInterface* simSceneInterface = &myAgentManager;
mySimulation = new DistributedSimulationConnection(*simSceneInterface,
DtSharedSettingsManager::instance(agentManager().de()));
mySimulation->connect(init);
// Add all models to the scene that may have already been encountered
// in the case where a previous onStart() was followed by an onStop().
for (unsigned int i=0; i<mySceneObjectAgentsList.size(); i++)
{
mySceneObjectAgentsList[i].first->addModel(
mySceneObjectAgentsList[i].second, 0);
}
// Add a detonation interaction callback
DtDetonationInteraction::addCallback(mySimulation->exerciseConn(), &processDetonationCb, this);
return mySimulation->connected();
}
bool DistributedSimulationDriver::onStop()
{
// NOTE: breakdown code goes here. Return false on bad status.
std::cout << "DistributedSimulationDriver::onStop(): " << std::endl;
if (mySimulation)
delete mySimulation;
mySimulation = 0;
// Remove all models from the scene
for (unsigned int i=0; i<mySceneObjectAgentsList.size(); i++)
{
mySceneObjectAgentsList[i].first->removeModel(
mySceneObjectAgentsList[i].second);
}
return true;
}
bool DistributedSimulationDriver::onTick()
{
// printout to show whether or not connected at the tick level
bool connState = mySimulation->connected();
if (connState)
{
int numread = mySimulation->exerciseConn()->drainInput();
std::cout << "." << numread;
}
else
std::cout << "x";
// rotate all models to the left.
for (unsigned int i=0; i<mySceneObjectAgentsList.size(); i++)
{
const DtTaitBryan orient(myRotationDegree, 0, 0);
mySceneObjectAgentsList[i].first->setOrientation(0, orient);
myRotationDegree -= 0.005;
if(myRotationDegree < 0.0)
{
myRotationDegree = 360.0;
}
}
return connState;
}
void DistributedSimulationDriver::processDetonationCb(DtDetonationInteraction* inter, void* usr)
{
((DistributedSimulationDriver*)usr)->processDetonation(inter);
}
void DistributedSimulationDriver::processDetonation(DtDetonationInteraction* inter)
{
std::cout << "((detonation interaction))";
std::cout << "D(" << inter->attackerId().entityNum() << "," << inter->targetId().entityNum() << "," << inter->result() << ")";
DtVector vect2 = inter->worldLocation();
DtVector local;
myAgentManager.de().sharedState().coordinateSystem().netToLocalPos(
inter->worldLocation(), local);
// Add a cow to the root node by creating an existing model and agent
// and setting the cow model definition into it.
DtModelAgent* simpleModel = DtModelAgent::create(myAgentManager);
DtSceneObjectAgent* sceneObjectAgent = DtSceneObjectAgent::create(myAgentManager);
sceneObjectAgent->setPosition(0, local);
sceneObjectAgent->setModelSet(0);
sceneObjectAgent->addModel(simpleModel, 0);
simpleModel->setModelDefinition("LifeformsAnimalsCow");
// Remember the agents for later removal of cows.
mySceneObjectAgentsList.push_back(std::make_pair(sceneObjectAgent, simpleModel));
}
}
}

DistributedSimulationPlugin5.h

/******************************************************************************
** Copyright (c) 2011 MAK Technologies, Inc.
** All rights reserved.
******************************************************************************/
#pragma once
// Setup proper plugin export symbol
#ifdef WIN32
#define DT_DE_PLUGIN_EXPORT_MACRO __declspec ( dllexport )
#else
#define DT_DE_PLUGIN_EXPORT_MACRO
#endif
// Declare & export the plugin initialization function (bool initDeModule(DtDe* de))
namespace makVrv { class DtDe; }
// Work function for the plugin initialization
void init(makVrv::DtDe& de);
// Callback to create the stateViewDriver

DistributedSimulationPlugin5.cxx

/******************************************************************************
** Copyright (c) 2011 MAK Technologies, Inc.
** All rights reserved.
******************************************************************************/
#include <vrvCore/DtDe.h>
#include <boost/bind.hpp>
using namespace makVrv;
using namespace makVrv::tutorialDistributedSimulation5;
{
// We're done with the signal, so disconnect from it
// Create the driver that will implement a distributed simulation
DistributedSimulationDriver* driver = new DistributedSimulationDriver(
de->agentManager(), "DistributedSimulationDriver5");
// After the driver is added to the display engine below, the DE will manage
// its memory. This driver will add itself to the connection list. Start
// it from the connection panel.
de->driverManager().addDriver(driver);
}
void init(DtDe& de)
{
// Ensure that init only gets called once
// (not strictly necessary here, but this is good practice in general)
// We only want to create the driver if we're running in master mode:
if (de.isInMasterMode())
{
// The driver must be created after the DE's initialization is
// finished, to make sure all the objects it uses exist.
}
}
{
// Setup the plugin. Normally, the init function and functionality
// should be in its own library.
init(*de);
return true;
}

DistributedSimulationConnection5.h

/******************************************************************************
** Copyright (c) 2011 MAK Technologies, Inc.
** All rights reserved.
******************************************************************************/
#pragma once
#include <boost/signal.hpp>
class DtExerciseConn;
namespace makVrv
{
namespace tutorialDistributedSimulation5
{
class DistributedSimulationConnection : public DtBaseConnection
{
public:
DistributedSimulationConnection(DtAgentManagerInterface& aSceneInterface,
DtSharedSettingsManager& settingsManager);
inline DtExerciseConn* exerciseConn()
{
return myConnection;
}
virtual bool connect(const DtExerciseConnInitializer& exConnInitializer);
virtual bool disconnect();
virtual bool connected() const;
boost::signal<void ()> signal_toBeDisconnected;
protected:
DtExerciseConn* myConnection;
};
}
}

DistributedSimulationConnection5.cxx

/******************************************************************************
** Copyright (c) 2014 MAK Technologies, Inc.
** All rights reserved.
******************************************************************************/
#define DtDIS 1
#include <vl/exerciseConn.h>
#include <vl/exerciseConnInitializer.h>
namespace makVrv
{
namespace tutorialDistributedSimulation5
{
DtSharedSettingsManager& settingsManager)
: DtBaseConnection(settingsManager, aSceneInterface)
, myConnection(0)
, myExConnInitializer(new DtExerciseConnInitializer())
{
}
DistributedSimulationConnection::~DistributedSimulationConnection(void)
{
}
bool DistributedSimulationConnection::connect(const DtExerciseConnInitializer& exConnInitializer)
{
*myExConnInitializer = exConnInitializer;
if (myConnection)
disconnect();
DtExerciseConn::InitializationStatus status = DtExerciseConn::DtINIT_SUCCESS;
try
{
myConnection = new DtExerciseConn(*myExConnInitializer, &status);
}
catch(...)
{
return false;
}
if(status != DtExerciseConn::DtINIT_SUCCESS)
{
return false;
}
return true;
}
bool DistributedSimulationConnection::disconnect()
{
try
{
delete myConnection;
myConnection = 0;
}
catch(...)
{
return false;
}
return true;
}
bool DistributedSimulationConnection::connected() const
{
return myConnection != 0;
}
}
}


Copyright © 2005-2018 VT MAK. All Rights Reserved (www.mak.com)