VR-Forces Developer's Guide
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
exampleCloudDriver

Table of Contents

Overview

This example is a plugin that creates a new driver. This driver reads a CSV file (clouds.csv), then dynamically places clouds in the scene.

Expected Result

TODO

Example details

The CSV file contains information about cloud layers and wind volumes. This example is meant to be used in flat earth projections only. The cloud layer coordinates are in database coordinates.

At each tick, the driver moves each cloud layer based on the wind volumes at its altitude.

Wind volumes are stored as DtWind classes and are declared in DtCloudDriverCommon.h. A wind volume consists of a direction in degrees from north to east, a minimum and maximum altitude, and a speed in meters per second.

/******************************************************************************
** Copyright (c) 2011 MAK Technologies, Inc.
** All rights reserved.
******************************************************************************/
#pragma once
#include <vector>
namespace makVrv
{
namespace vrvExampleCloudDriver
{
class DtWind
{
public:
DtWind(double directionN2E,
double minAltitude = 0,
double maxAltitude = 100000,
double speedInMps = 100);
bool withinAltitude(double alt) const;
double dirNtoE;
double northVel;
double eastVel;
double minAlt;
double maxAlt;
double speed;
};
typedef std::vector<DtWind> WindList;
}
}

The driver's onStart() method does two things: First it connects to the DtEnvironmentSignaler's signal_cloudLayerAdded and signalCloudLayerToBeDestroyed signals. These are used to keep track of the current cloud layers in the scene.

DtEnvironmentSignaler::instance(myAgentManager.de()).signal_cloudLayerAdded.connect(
std::bind(&DtCloudDriver::on_cloudLayerAdded,this,_1));
DtEnvironmentSignaler::instance(myAgentManager.de()).signal_cloudLayerToBeDestroyed.connect(
std::bind(&DtCloudDriver::on_cloudLayerDestroyed,this,_1));

Then it parses the CSV file first and then creates the cloud layers and wind volumes.

DtCloudParser parser;
if (!parser.parseFile("../examples/exampleCloudDriver/clouds.csv"))
{
DtWarn << "Error parsing cloud file clouds.csv" << std::endl;
}
else
{
makeClouds(parser);
makeWind(parser);

In the driver's onTick() method, the cloud layer list is iterated over, and for each wind volume, if the cloud layer's altitude falls within the wind volume, it is moved the appropriate distance.

for (int index = 0; index < myCloudLayers.size(); ++index)
{
makArchives::DtCloudLayerRecord& cloud = myCloudLayers[index];
bool changed = false;
double cloudAltitude = cloud.position()[2];
for(DtWind& wind : myWindList)
{
if (wind.withinAltitude(cloudAltitude))
{
double eastChange = wind.eastVel * dt;
double northChange = wind.northVel * dt;
cloud.setPosition(cloud.position()[0] + eastChange,
cloud.position()[1] + northChange,cloud.position()[2]);
changed = true;

The plugin initialization is performed in exampleCloudDriverPluginInit.cxx. This consists of the exported function initDeModule(), and a couple of other helper functions. The init() function connects to the display engine's signal_postInitialize signal. After the DtDe has been initialized, installDriver() will be called, which will install the DtCloudDriver into the driver manager, and set it to automatically start.

Building the Example

VR-Vantage includes pre-built versions of the example plug-in. To build it yourself, follow the instructions at Building VR-Vantage Examples, Applications, and Plug-ins.

Running the Example

This example is a plug-in. You can run it by running ./bin64/exampleCloudDriverPlugin_stealth.bat (on Windows) or ./bin64/exampleCloudDriverPlugin_stealth.sh (on Linux). For more information about running examples, please see Running Applications and Examples.


Example Source Files


DtCloudDriver.cxx

/******************************************************************************
** Copyright (c) 2023 MAK Technologies, Inc.
** All rights reserved.
******************************************************************************/
#include "DtCloudDriver.h"
#include "DtCloudParser.h"
#include <vrvCore/DtDe.h>
#include <matrix/vlMath.h>
#include <math.h>
#include <algorithm>
#include <functional>
#include <vlutil/vlPrint.h>
// Use the VR-Vantage namespace. All classes in VR-Vantage are in this namespace.
using namespace makVrv;
namespace makVrv
{
namespace vrvExampleCloudDriver
{
DtCloudDriver::DtCloudDriver(DtAgentManager& am)
: makVrv::DtDriver(am,"Example Cloud Driver")
, myLastUpdate(0)
{
}
DtCloudDriver::~DtCloudDriver()
{
}
const std::string& DtCloudDriver::className() const
{
static std::string name = "Cloud Driver";
return name;
}
bool DtCloudDriver::onStart()
{
DtEnvironmentSignaler::instance(myAgentManager.de()).signal_cloudLayerAdded.connect(
std::bind(&DtCloudDriver::on_cloudLayerAdded,this,_1));
DtEnvironmentSignaler::instance(myAgentManager.de()).signal_cloudLayerToBeDestroyed.connect(
std::bind(&DtCloudDriver::on_cloudLayerDestroyed,this,_1));
DtCloudParser parser;
if (!parser.parseFile("../examples/exampleCloudDriver/clouds.csv"))
{
DtWarn << "Error parsing cloud file clouds.csv" << std::endl;
}
else
{
makeClouds(parser);
makeWind(parser);
}
myLastUpdate = myAgentManager.de().simulationTime();
return true;
}
bool DtCloudDriver::onStop()
{
DtEnvironmentSignaler::instance(myAgentManager.de()).signal_cloudLayerAdded.disconnect(
std::bind(&DtCloudDriver::on_cloudLayerAdded,this,_1));
DtEnvironmentSignaler::instance(myAgentManager.de()).signal_cloudLayerToBeDestroyed.disconnect(
std::bind(&DtCloudDriver::on_cloudLayerDestroyed,this,_1));
return true;
}
bool DtCloudDriver::onTick()
{
//Only works with flat terrains.
if(myAgentManager.de().sharedState().coordinateSystem().isGeocentric())
{
return true;
}
double curTime = myAgentManager.de().simulationTime();
double dt = curTime - myLastUpdate;
myLastUpdate = curTime;
for (int index = 0; index < myCloudLayers.size(); ++index)
{
makArchives::DtCloudLayerRecord& cloud = myCloudLayers[index];
bool changed = false;
double cloudAltitude = cloud.position()[2];
for(DtWind& wind : myWindList)
{
if (wind.withinAltitude(cloudAltitude))
{
double eastChange = wind.eastVel * dt;
double northChange = wind.northVel * dt;
cloud.setPosition(cloud.position()[0] + eastChange,
cloud.position()[1] + northChange,cloud.position()[2]);
changed = true;
}
}
if (changed)
{
myAgentManager.de().scene().environment().
setCloudLayerPosition(index,
cloud.position()[0],
cloud.position()[1]);
}
}
return true;
}
void DtCloudDriver::makeClouds(const DtCloudParser& parser)
{
myAgentManager.de().scene().environment().getRecord(envRecord);
envRecord.cloudLayers().clear();
myCloudLayers.clear();
//make some clouds
std::copy(parser.cloudLayers().begin(),
parser.cloudLayers().end(),
back_inserter(envRecord.cloudLayers()));
myAgentManager.de().scene().environment().setFromRecord(envRecord);
}
void DtCloudDriver::makeWind(const DtCloudParser& parser)
{
myWindList.clear();
std::copy(parser.windList().begin(),
parser.windList().end(),
back_inserter(myWindList));
}
void DtCloudDriver::on_cloudLayerDestroyed(int index)
{
DtInfo << "[DESTROYED] Cloud layer " << index << std::endl;
if (index < myCloudLayers.size())
{
myCloudLayers.erase(myCloudLayers.begin() + index);
}
}
void DtCloudDriver::on_cloudLayerAdded(int index)
{
DtInfo << "[ADDED] Cloud layer " << index << std::endl;
if (myCloudLayers.size() == index)
{
myAgentManager.de().scene().environment().getRecord(envRecord);
myCloudLayers.push_back(envRecord.cloudLayers()[index]);
}
}
}
}

DtCloudDriver.h

/******************************************************************************
** Copyright (c) 2011 MAK Technologies, Inc.
** All rights reserved.
******************************************************************************/
#pragma once
#include "exampleCloudDriverPlugin.h" // for exports
namespace makVrv
{
class DtDe;
namespace vrvExampleCloudDriver
{
class DtCloudParser;
class DT_DLL_EXAMPLECLOUDDRIVER DtCloudDriver : public makVrv::DtDriver
{
public:
DtCloudDriver(DtAgentManager& am);
virtual ~DtCloudDriver();
virtual const std::string& className() const;
protected:
virtual bool onStart();
virtual bool onStop();
virtual bool onTick();
void makeClouds(const DtCloudParser& parser);
void makeWind(const DtCloudParser& parser);
void on_cloudLayerAdded(int index);
void on_cloudLayerDestroyed(int index);
protected:
double myLastUpdate;
WindList myWindList;
};
}
}

DtCloudDriverCommon.cxx

/******************************************************************************
** Copyright (c) 2011 MAK Technologies, Inc.
** All rights reserved.
******************************************************************************/
#include <matrix/vlMath.h>
#include <math.h>
namespace makVrv
{
namespace vrvExampleCloudDriver
{
DtWind::DtWind(double directionN2E, double minAltitude, double maxAltitude, double speedInMps) :
dirNtoE(directionN2E)
, minAlt(minAltitude)
, maxAlt(maxAltitude)
, speed(speedInMps)
{
eastVel = cos(DtDeg2Rad(dirNtoE)) * speed;
northVel = sin(DtDeg2Rad(dirNtoE)) * speed;
}
bool DtWind::withinAltitude(double alt) const
{
return alt >= minAlt && alt <= maxAlt;
}
}
}

DtCloudDriverCommon.h

/******************************************************************************
** Copyright (c) 2011 MAK Technologies, Inc.
** All rights reserved.
******************************************************************************/
#pragma once
#include <vector>
namespace makVrv
{
namespace vrvExampleCloudDriver
{
class DtWind
{
public:
DtWind(double directionN2E,
double minAltitude = 0,
double maxAltitude = 100000,
double speedInMps = 100);
bool withinAltitude(double alt) const;
double dirNtoE;
double northVel;
double eastVel;
double minAlt;
double maxAlt;
double speed;
};
typedef std::vector<DtWind> WindList;
}
}

DtCloudParser.cxx

/******************************************************************************
** Copyright (c) 2011 MAK Technologies, Inc.
** All rights reserved.
******************************************************************************/
#include "DtCloudParser.h"
#include <vlutil/vlPrint.h>
#include <fstream>
// Use the VR-Vantage namespace. All classes in VR-Vantage are in this namespace.
using namespace makVrv;
namespace makVrv
{
namespace vrvExampleCloudDriver
{
DtCloudParser::DtCloudParser()
{
}
DtCloudParser::~DtCloudParser()
{
}
bool DtCloudParser::parseFile(std::string fn)
{
std::ifstream f(fn.c_str());
char buf[1024];
if (!f)
{
return false;
}
while (f.good())
{
f.getline(buf, 1024);
parseLine(buf);
}
return true;
}
void DtCloudParser::parseLine(std::string line)
{
// skip blanks and commented lines
if (line.length() == 0 || line[0] == ';')
{
return;
}
const std::string delim(", ");
std::string::size_type idx = line.find_first_of(delim);
if (idx == std::string::npos)
{
return;
}
std::string type = line.substr(0, idx);
line.erase(0, idx);
if (type == "CLOUD")
{
parseCloud(line);
}
else if (type == "WIND")
{
parseWind(line);
}
}
void DtCloudParser::parseCloud(std::string& line)
{
std::vector<std::string> tokens;
tokenize(line, tokens);
if (tokens.size() == 0)
{
return;
}
rec.setType(tokens[0]);
rec.setPosition(tokens.size() > 1 ? atof(tokens[1].c_str()) : 0.0,
tokens.size() > 2 ? atof(tokens[2].c_str()) : 0.0,
tokens.size() > 3 ? atof(tokens[3].c_str()) : 0.0);
rec.setWidth(tokens.size() > 4 ? atof(tokens[4].c_str()) : 0.0);
rec.setLength(tokens.size() > 5 ? atof(tokens[5].c_str()) : 0.0);
rec.setThickness(tokens.size() > 6 ? atof(tokens[6].c_str()) : 0.0);
rec.setDensity(tokens.size() > 7 ? atof(tokens[7].c_str()) : 0.0);
rec.setEnabledFlag(true);
myCloudLayers.push_back(rec);
}
void DtCloudParser::parseWind(std::string& line)
{
std::vector<std::string> tokens;
tokenize(line, tokens);
if (tokens.size() < 4)
{
return;
}
double direction = atof(tokens[0].c_str());
double minAlt = atof(tokens[1].c_str());
double maxAlt = atof(tokens[2].c_str());
double speed = atof(tokens[3].c_str());
myWindList.push_back(DtWind(
direction, minAlt, maxAlt, speed));
}
void DtCloudParser::tokenize(const std::string& line,
std::vector<std::string>& tokens)
{
const std::string delim(", ");
std::string::size_type begIdx, endIdx;
std::string token;
begIdx = line.find_first_not_of(delim);
while (begIdx != std::string::npos)
{
endIdx = line.find_first_of(delim, begIdx);
if (endIdx == std::string::npos)
{
endIdx = line.length();
}
token = line.substr(begIdx, endIdx - begIdx);
tokens.push_back(token);
begIdx = line.find_first_not_of(delim, endIdx);
}
}
DtCloudParser::cloudLayers() const
{
return myCloudLayers;
}
const WindList& DtCloudParser::windList() const
{
return myWindList;
}
}
}

DtCloudParser.h

/******************************************************************************
** Copyright (c) 2011 MAK Technologies, Inc.
** All rights reserved.
******************************************************************************/
#pragma once
namespace makVrv
{
namespace vrvExampleCloudDriver
{
class DtCloudParser
{
public:
bool parseFile(std::string fn);
cloudLayers() const;
const WindList& windList() const;
protected:
void parseLine(std::string line);
void parseCloud(std::string& line);
void parseWind(std::string& line);
void tokenize(const std::string& line, std::vector<std::string>& list);
};
}
}

exampleCloudDriverPluginInit.cxx

/******************************************************************************
** Copyright (c) 2023 MAK Technologies, Inc.
** All rights reserved.
******************************************************************************/
#include "DtCloudDriver.h"
#include <vrvCore/DtDe.h>
#include <functional>
static vrvSignalsLib::connection postInitializeConnection;
{
{
return true;
}
return false;
}
namespace makVrv
{
namespace vrvExampleCloudDriver
{
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 are 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.
postInitializeConnection = de.signal_postInitialize.connect(std::bind(
&installDriver, std::ref(de) ));
}
}
void installDriver(DtDe& de)
{
DtCloudDriver* driver = new DtCloudDriver( de.agentManager());
driver->setAutoStart(true);
// prevent the driver from being added to the connections list
driver->setIsUserControllable(false);
de.driverManager().addDriver(driver);
}
}
}

exampleCloudDriverPluginInit.h

/******************************************************************************
** Copyright (c) 2011 MAK Technologies, Inc.
** All rights reserved.
******************************************************************************/
#ifndef exampleCloudDriverPluginInit_H_
#define exampleCloudDriverPluginInit_H_
//Get proper local export symbol
//Setup proper plugin export symbol
#define DT_DE_PLUGIN_EXPORT_MACRO DT_DLL_EXAMPLECLOUDDRIVER
//Export plugin function void initDeModule(DtDe*);
namespace makVrv
{
class DtDe;
namespace vrvExampleCloudDriver
{
void installDriver(DtDe& de);
}
}
#endif

[<< Examples] [Home] [Top of Page]


Document ID: Generated on Thu Oct 23 22:29:17 EDT 2025 from SVN revision 280951
Copyright © 2005-2024 MAK Technologies. All Rights Reserved (www.mak.com)