VR-Forces 4.5 Class Documentation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
exampleSymbolDecoration

Introduction

The purpose of this example is to show how to add a new Symbol Decoration to a Decoration Set. A Symbol Decoration is a label plus additional text that can be displayed next to an entity icon on a 2D (PVD or XR) display. A Decoration Set is a collection of Symbol Decorations. VR-Vantage defines Decoration Sets for entities, props, and tactical graphics. In this examble a Symbol Decoration that consists of a list of DIS / RPR FOM articulated part ids, called "Articulated Part IDs" is added to the Decoration Set for entities. The user will be able to turn this new Symbol Decoration on or off for all entities from the Settings / Display / Symbol Decorations dialog.

Plugin Initialization

When a plugin is loaded, VR-Vantage invokes its initDeModule function. This plugin simply calls its init function from initDeModule.

{
// Setup the plugin. Normally, the init function and functionality
// should be in its own library.
init(*de);
return true;
}

The init function ensures that it will only ever be initialize once (even if the function is called multiple times).

Provided the plugin has been loaded into a VR-Vantage application with a master display engine, the plugin registers a creator for the DtArtPartSymbolDecoration it will display (defined in DtArtPartSymbolDecoration.cxx) with the DtSymbolDecorationFactory.

DtSymbolDecorationFactory::instance(de).registerCreator(
new DtArtPartSymbolDecorationCreator());

Finally, the init function connects to the display engine's post initialize signal, requesting that the local function load be invoked when the display engine is initialized.

&load, &de));

When the display engine has been fully initialized, it raises the post initialize signal, which causes the load function to be called. The load function disconnects from the post initialize signal (it's no longer needed) and asks for a DtWriteSettingsLock on the DtSymbolDecorationSettings object (this object is shared across multiple threads, so a mutex must be used).

DtWriteSettingsLock<DtSymbolDecorationSettings>
settings(DtSharedSettingsManager::instance(*de));

Once the function is cleared to write, it gets a copy of the "defaultEntity" Decoration Set

DtSymbolDecorationSettings::DecorationSet decorationSet =
settings->getOrCreateDecorationSet("defaultEntity");

adds the "DtArtPartSymbolDecoration" Symbol Decoration to the copy

decorationSet.insert("DtArtPartSymbolDecoration");

and then sets the Decoration Set for "defaultEntity" to be the modified Decoration Set.

settings->setDecorationSet("defaultEntity", decorationSet);

Articulated Part Symbol Decoration

The DtArtPartSymbolDecoration class implements the new Articulated Part Symbol Decoration. Symbol Decorations are created for each object as it is discovered. If the current display settings indicate that the Articulated Part Symbol Decoration should be visible, then its visualize method will be called after it is created (or when the Articulated Part Symbol Decoration type is enabled). The visualize method tells the Decoration Set visualizer that it will be a Text / Value type decoration, and provides the label for the text portion.

myParentVisualizer.widget()->setTypeValueText(
myIndex, DtUnicode::fromAscii("Articulated Part IDs"));

It creates an updater agent, which in turn causes an updater to be created for each rendering engine (see Articulated Part Symbol Decoration Updater) that will periodically update the label, in case any parts areadded or removed.

myUpdater = DtArtPartDecorationUpdaterAgent::create(
myParentVisualizer.simulation().sceneInterface());

The updater is initialized with a pointer to the scene object of the visualizer responsible for visualizing the entire Decoration Set for that object,

myUpdater->setSceneObject(myParentVisualizer.sceneObject());

the id of the widget object owned by the Decoration Set,

myUpdater->attachAttributeGroupWidget(myParentVisualizer.widget()->uniqueId());

and with the index in the list of displayed Symbol Decorations that the Articulated Part Symbol Decoration will use.

myUpdater->setAttributeIndex(myIndex);

Conversely, unvisualize is called when the symbol decoration should be hidden; it sets the Symbol Decoration type for its index to Null, and deletes the DtArtPartDecorationUpdater created in visualize.

if (myParentVisualizer.widget())
{
myParentVisualizer.widget()->setTypeNull(myIndex);
}
delete myUpdater;
myUpdater = 0;

Articulated Part Symbol Decoration Updater

DtArtPartSymbolDecoration creates a DtArtPartDecorationUpdaterAgent when visualize is called. This causes an instance of the distributed object DtArtPartDecorationUpdater to be created on each rendering engine (master display engine and any Vr-Vantage remote display engines that may be in use).

The updater inherits from DtTickable; the DtArtPartDecorationUpdater constructor registers the updater with the DtTickableManager, will will call the virtual needsUpdate method each redner frame, and if needsUpdate returns true, will call the update method.

NeedsUpdate checks that it has a valid pointer to the widget to be updated, a valid index into that widget, and checks a timer variable which determines if the Symbol Decoration is due for an update.

if (!myAttributeGroupWidget // no widget to update
|| myLastSymbolUpdateTime > tNow - 1.0 // only update once/second for efficiency
|| myLabelIndex == -1)// no label in the widget has been assigned yet))
{
return false;
}
return true;

If any of these tests fail, needsUpdate returns false; otherwise needsUpdate returns true, and udpate is called.

myLastSymbolUpdateTime = simTime;

Update gets the scene object the updater is attached to. Note that this will be the scene object used to visualize the 2D representation, as Symbol Decorations are a 2D feature.

DtSceneObject* so = mySceneObject;

The scene object contains the elementID of the element being visualized. That can be used to look up the scene object of the 3D representation (which will have the articulated part information we want).

if (so)
{
// get 3d model set scene object for the same simulated element
so = findSceneObjectFor( so->elementID(), DtSceneObject::ModelSet_3D );
}

Provided the 3D scene object is found, the updater then iterates through the list of models held by the scene object, using a dynamic cast to find models that are of type DtArticulatedModel. For each DtArticulatedModel found, the updater gets the part id and adds it to a vector of part ids.

for (DtSceneObject::ModelList::iterator iter = models.begin();
iter != models.end(); ++iter)
{
DtArticulatedModel* artModel =
dynamic_cast<DtArticulatedModel*>(iter->model);
if (artModel)
{
artModel->getParts(parts); // appends to the end of parts
}
}

The updater iterates over the vector of part ids, converting each to string form and adding it to a character buffer.

unsigned int bufSize = 10 * parts.size() + 1;
char* bufStart = new char[bufSize];
char* buf = bufStart;
bufStart[0] = '\0'; // make sure the string is null terminated even when there are no parts
for (DtArticulatedModel::PartList::iterator iter = parts.begin();
iter != parts.end(); ++iter)
{
int partId = *iter;
int sizeLeft = bufSize - (buf - bufStart);
int written = DtSnprintf(buf, sizeLeft, "%i ", partId);
buf += written;
}

Finally, the value field for the Symbol Decoration is set to the buffer.

myAttributeGroupWidget->setValueTextValue(
myLabelIndex, DtUnicode::fromAscii(bufStart));

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 ./bin/exampleSymbolDecoration_stealth.bat (on Windows) or ./bin/exampleSymbolDecoration_stealth.sh (on Linux). For more information about running examples, please see Running Applications and Examples.

Example Source Files


exampleSymbolDecorationPlugin.h

/******************************************************************************
** Copyright (c) 2010 MAK Technologies, Inc.
** All rights reserved.
******************************************************************************/
#pragma once
// Get proper local export symbol
// Setup proper plugin export symbol
#define DT_DE_PLUGIN_EXPORT_MACRO DT_DLL_EXAMPLESYMBOLDECORATION
// Declare & export the plugin initialization function (bool initDeModule(DtDe* de))
namespace makVrv
{
class DtDe;
}
// Work function for the plugin initialization

exampleSymbolDecorationPlugin.cxx

/******************************************************************************
** Copyright (c) 2010 MAK Technologies, Inc.
** All rights reserved.
******************************************************************************/
#include <vrvCore/DtDe.h>
using namespace makVrv;
void load(DtDe* de)
{
// We're done with the signal, so disconnect from it
de->signal_postInitialize.disconnect(boost::bind(&load, de));
// The symbol decoration settings are shared across multiple threads, so
// they're controlled by the DtSharedSettingsManager. To write to them,
// we need to get a write locked settings object from the manager:
{
// Add the art part decoration to the "defaultEntity" decoration set
settings->getOrCreateDecorationSet("defaultEntity");
decorationSet.insert("DtArtPartSymbolDecoration");
settings->setDecorationSet("defaultEntity", decorationSet);
}
} // end of method
void init(DtDe& de)
{
// Ensure that init only gets called once
// (not strictly necessary here, but this is good practice in general)
if (de.isInMasterMode())
{
// The new decoration must be added to a decoration set; the settings
// manager that owns decoration sets can't be used until after the
// display engine is initialized, so we connect to its post initialize
// signal and access the settings later.
&load, &de));
}
} // end of method
{
// Setup the plugin. Normally, the init function and functionality
// should be in its own library.
init(*de);
return true;
}

DtArtPartSymbolDecoration.h

/*****************************************************************************
* Copyright (c) 2012 MAK Technologies, Inc.
* All rights reserved.
*****************************************************************************/
#pragma once
namespace makVrv
{
class DtArtPartDecorationUpdaterAgent;
class DT_DLL_EXAMPLESYMBOLDECORATION DtArtPartSymbolDecoration
: public DtSymbolDecoration
{
public:
DtArtPartSymbolDecoration( unsigned int index,
DtSymbolDecorationVisualizer& parentVisualizer );
virtual ~DtArtPartSymbolDecoration();
virtual void visualize();
virtual void unvisualize();
protected:
unsigned int myIndex;
DtSymbolDecorationVisualizer& myParentVisualizer;
DtArtPartDecorationUpdaterAgent* myUpdater;
};
class DT_DLL_EXAMPLESYMBOLDECORATION DtArtPartSymbolDecorationCreator
: public DtSymbolDecorationCreator
{
public:
DtArtPartSymbolDecorationCreator();
virtual ~DtArtPartSymbolDecorationCreator();
virtual DtSymbolDecoration* create( DtSymbolDecorationVisualizer& parentVisualizer );
virtual DtSymbolDecorationCreator* clone();
virtual const std::string& displayName();
virtual const std::string& decorationClassName();
virtual const std::string& tag();
};
}

DtArtPartSymbolDecoration.cxx

/*****************************************************************************
* Copyright (c) 2012 MAK Technologies, Inc.
* All rights reserved.
*****************************************************************************/
#include "DtArtPartDecorationUpdaterAgent.hpp"
#include <vrvCore/DtAttributeGroupWidgetAgent.hpp>
#include <vrvCore/DtSceneObjectAgent.hpp>
#include <vrvCore/DtSymbolDecorationUpdaterAgent.hpp>
namespace makVrv
{
unsigned int index, DtSymbolDecorationVisualizer& parentVisualizer )
: DtSymbolDecoration()
, myIndex( index )
, myParentVisualizer( parentVisualizer )
, myUpdater( 0 )
{
}
DtArtPartSymbolDecoration::~DtArtPartSymbolDecoration()
{
if ( myParentVisualizer.widget() )
{
myParentVisualizer.widget()->setTypeNull(myIndex);
}
delete myUpdater;
myUpdater = 0;
}
void DtArtPartSymbolDecoration::visualize()
{
myParentVisualizer.widget()->setTypeValueText(
myIndex, DtUnicode::fromAscii("Articulated Part IDs"));
myUpdater = DtArtPartDecorationUpdaterAgent::create(
myParentVisualizer.simulation().sceneInterface());
myUpdater->setSceneObject(myParentVisualizer.sceneObject());
myUpdater->attachAttributeGroupWidget(myParentVisualizer.widget()->uniqueId());
myUpdater->setAttributeIndex(myIndex);
}
void DtArtPartSymbolDecoration::unvisualize()
{
if (myParentVisualizer.widget())
{
myParentVisualizer.widget()->setTypeNull(myIndex);
}
delete myUpdater;
myUpdater = 0;
}
//
// DtArtPartSymbolDecorationCreator method definitions.
//
DtArtPartSymbolDecorationCreator::DtArtPartSymbolDecorationCreator()
{
}
DtArtPartSymbolDecorationCreator::~DtArtPartSymbolDecorationCreator()
{
}
DtSymbolDecoration* DtArtPartSymbolDecorationCreator::create(
DtSymbolDecorationVisualizer& parentVisualizer )
{
return new DtArtPartSymbolDecoration(
parentVisualizer.nextLabelIndex(), parentVisualizer);
}
DtSymbolDecorationCreator* DtArtPartSymbolDecorationCreator::clone()
{
return new DtArtPartSymbolDecorationCreator();
}
const std::string& DtArtPartSymbolDecorationCreator::displayName()
{
static std::string name("Articulated Parts");
return name;
}
const std::string& DtArtPartSymbolDecorationCreator::decorationClassName()
{
static std::string name("DtArtPartSymbolDecoration");
return name;
}
const std::string& DtArtPartSymbolDecorationCreator::tag()
{
static std::string tag("");
return tag;
}
}

DtArtPartDecorationUpdater.h

/******************************************************************************
** Copyright (c) 2012 MAK Technologies, Inc.
** All rights reserved.
******************************************************************************/
#pragma once
#include <vrvCore/DtDe.h>
#include <string>
namespace makVrv
{
class DtAttributeGroupWidget;
class DtSceneObject;
class DT_DLL_EXAMPLESYMBOLDECORATION DtArtPartDecorationUpdater : public DtTickable
{
public:
DtArtPartDecorationUpdater(DtDe& de, DtUniqueID id);
virtual ~DtArtPartDecorationUpdater();
virtual bool needsUpdate(DtTime tNow);
virtual void update(double simTime);
virtual void setSceneObject(DtSceneObject* sceneObject);
virtual void attachAttributeGroupWidget(DtUniqueID id);
virtual void setAttributeIndex(unsigned int index);
protected:
DtSceneObject* findSceneObjectFor(
const DtElementID& elementId, DtSceneObject::ModelSet modelSet);
virtual void slot_sceneObjectToBeDeleted(const DtUniqueID& id);
protected:
DtDe& myDe;
DtSceneObject* mySceneObject;
DtUniqueID myUniqueId;
float myLastSymbolUpdateTime;
DtAttributeGroupWidget* myAttributeGroupWidget;
int myLabelIndex;
};
}

DtArtPartDecorationUpdater.cxx

/******************************************************************************
** Copyright (c) 2012 MAK Technologies, Inc.
** All rights reserved.
******************************************************************************/
//#include <vrvCore/DtDeadReckonGroundClampUpdater.h>
#include <matrix/vlDcm.h>
namespace makVrv
{
DtDe& de, DtUniqueID id)
: DtTickable(&de.renderer().tickableManager())
, myLastSymbolUpdateTime(0.0)
, myAttributeGroupWidget(0)
, myLabelIndex(-1)
, mySceneObject(0)
, myDe(de)
, myUniqueId(id)
{
}
DtArtPartDecorationUpdater::~DtArtPartDecorationUpdater()
{
myAttributeGroupWidget = 0;
try
{
myDe.renderer().tickableManager().removeTickableObject(this);
}
catch (DtCorruptedState* err)
{
myDe.log().out(DtDebugLog::Debug) <<
"DtTickableManager failed to remove DtSymbolDecorationUpdater : " <<
err->message() << std::endl;
}
setSceneObject(NULL);
}
bool DtArtPartDecorationUpdater::needsUpdate(DtTime tNow)
{
if (!myAttributeGroupWidget // no widget to update
|| myLastSymbolUpdateTime > tNow - 1.0 // only update once/second for efficiency
|| myLabelIndex == -1)// no label in the widget has been assigned yet))
{
return false;
}
return true;
}
void DtArtPartDecorationUpdater::update(double simTime)
{
myLastSymbolUpdateTime = simTime;
// Get the 3D scene object the updater is attached to, and count the
// articulated parts in any articulated models that it owns
DtSceneObject* so = mySceneObject;
if (so)
{
// get 3d model set scene object for the same simulated element
so = findSceneObjectFor( so->elementID(), DtSceneObject::ModelSet_3D );
}
if (so)
{
// Get the articulated parts owned by the scene object associated
// with this decoration, and update the label.
DtArticulatedModel::PartList parts;
DtSceneObject::ModelList& models = so->models();
for (DtSceneObject::ModelList::iterator iter = models.begin();
iter != models.end(); ++iter)
{
DtArticulatedModel* artModel =
dynamic_cast<DtArticulatedModel*>(iter->model);
if (artModel)
{
artModel->getParts(parts); // appends to the end of parts
}
}
// build a string containing a list of the articulated part ids
unsigned int bufSize = 10 * parts.size() + 1;
char* bufStart = new char[bufSize];
char* buf = bufStart;
bufStart[0] = '\0'; // make sure the string is null terminated even when there are no parts
for (DtArticulatedModel::PartList::iterator iter = parts.begin();
iter != parts.end(); ++iter)
{
int partId = *iter;
int sizeLeft = bufSize - (buf - bufStart);
int written = DtSnprintf(buf, sizeLeft, "%i ", partId);
buf += written;
}
// update the label to list the articulated part ids
myAttributeGroupWidget->setValueTextValue(
myLabelIndex, DtUnicode::fromAscii(bufStart));
delete [] bufStart;
}
}
void DtArtPartDecorationUpdater::attachAttributeGroupWidget(DtUniqueID id)
{
myAttributeGroupWidget = 0;
DtAgentUpdateResolverInterface* agentUpdater =
myDe.agentManager().findUpdater(id);
if (agentUpdater)
{
myAttributeGroupWidget =
agentUpdater->castObjectTypeFromUpdater<DtAttributeGroupWidget>
("DtWidget");
}
}
void DtArtPartDecorationUpdater::setSceneObject(DtSceneObject* sceneObject)
{
if (mySceneObject)
{
mySceneObject->signal_sceneObjectToBeDeleted.disconnect(boost::bind(
&DtArtPartDecorationUpdater::slot_sceneObjectToBeDeleted, this, _1));
}
mySceneObject = sceneObject;
if (mySceneObject)
{
mySceneObject->signal_sceneObjectToBeDeleted.connect(boost::bind(
&DtArtPartDecorationUpdater::slot_sceneObjectToBeDeleted, this, _1));
}
}
void DtArtPartDecorationUpdater::slot_sceneObjectToBeDeleted(const DtUniqueID& id)
{
if (mySceneObject && mySceneObject->uniqueId() == id)
{
setSceneObject(NULL);
}
}
void DtArtPartDecorationUpdater::setAttributeIndex(unsigned int index)
{
myLabelIndex = index;
}
DtSceneObject* DtArtPartDecorationUpdater::findSceneObjectFor(
const DtElementID& elementId, DtSceneObject::ModelSet modelSet)
{
DtElementData::SceneObjectIdList sceneObjectIds;
DtElementData& mapper = myDe.dataBank().elementData();
mapper.getSceneObjectIds(elementId, sceneObjectIds, modelSet);
if (sceneObjectIds.size() && sceneObjectIds[0])
{
// look up object given id
DtAgentUpdateResolverInterface* updater =
myDe.agentManager().findUpdater(sceneObjectIds[0]);
if(updater)
{
return updater->castObjectTypeFromUpdater<DtSceneObject>(
"DtSceneObject");
}
}
return 0;
}
}

Document ID: Generated on Thu Mar 23 18:54:12 EDT 2017 from SVN revision 174804
Copyright © 2005-2017 VT MÄK. All Rights Reserved (www.mak.com)