VR-Vantage 2.4 API Documentation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
exampleConnectionObjects

The DtDataBank contains simulation-specific and element-specific data elements.

However there is substantial overlap - VR-Link driver's Marking Text is an element (that comes from that driver) Display Name. Element Data is, for the most part, static, and created when the Element itself is created. Simulation Data, on the other hand, contains both static and dynamic data.

Recently, we have added more of the static simulation data to the element data as element attributes, because element data is easier to work with and faster/cheaper to retrieve. In addition to the the already existing Display Name attribute, there is now a Connection ID attribute and a Connection Entity Type attribute. These are whatever a particular connection uses for an ID and entity type, in string form. For example, an element from a DIS connection might have a connection ID of "3001:1:1" and a connection entity type of "1:225:1:1:1:0:0". An element created by a CIGI connection, on the other hand, might have an connection ID of "5" and a connection Entity Type of "17".

It is common for users who are used to working in a DIS or HLA environment to want to look up elements by a connection ID or Marking Text, for example. Connection objects makes that much easier to do.

The exampleConnectionObjects example shows the signal that is raised with all the elements whose attribute data has been received that frame; elements can be added to indices or sets based on attribute data at that time. It builds an index of element IDs to Marking Text (Display Name) and vice versa. The example can easily be extended to build similar indices using connection ID attributes.

Example Source Files


DtConnectionObjects.cxx

/*****************************************************************************
* Copyright (c) 2017 MAK Technologies, Inc.
* All rights reserved.
*****************************************************************************/
#include <vrvCore/DtDe.h>
#include <boost/unordered_map.hpp>
// Use the VR-Vantage namespace.
// All classes in VR-Vantage are in this namespace.
namespace makVrv
{
: myDe( de )
{
myDe.dataBank().elementData().signal_elementsInitialized.connect(
boost::bind( &DtConnectionObjects::slot_elementsReadyToProcess, this, _1 ) );
myDe.dataBank().elementData().signal_elementsToBeRemoved.connect(
boost::bind( &DtConnectionObjects::slot_elementsRemoved, this, _1 ) );
}
DtConnectionObjects::~DtConnectionObjects()
{
myDe.dataBank().elementData().signal_elementsInitialized.disconnect(
boost::bind( &DtConnectionObjects::slot_elementsReadyToProcess, this, _1 ) );
myDe.dataBank().elementData().signal_elementsToBeRemoved.disconnect(
boost::bind( &DtConnectionObjects::slot_elementsRemoved, this, _1 ) );
}
DtSceneObject* DtConnectionObjects::sceneObjectFromSceneObjectId( DtUniqueID sceneObjId )
{
DtAgentUpdateResolverInterface* resolver = myDe.agentManager().findUpdater( sceneObjId );
if( resolver )
{
return resolver->castObjectTypeFromUpdater<DtSceneObject>( "DtSceneObject" );
}
return 0;
}
// A useful utility
DtSceneObject* DtConnectionObjects::sceneObjectFromElementId( DtElementID elementId, int modelSet )
{
DtElementData::SceneObjectIdList idList;
// Scene object id for given modelset (5) is 2D icons; use -1 for all
// model sets
myDe.dataBank().elementData().getSceneObjectIds( elementId, idList, modelSet );
if ( idList.size() == 0 )
{
return 0;
}
return sceneObjectFromSceneObjectId( idList.front() );
}
// Iterating through this list, iterator::first will provide all the display names;
// iterator::second, all the elementIDs
const DtConnectionObjects::DisplayNameToElementIdMap& DtConnectionObjects::displayNames() const
{
return myDisplayNameToElementIdMap;
}
// Iterating through this list, iterator::first will provide all the scene objects;
// iterator::second, all the elementIDs
const DtConnectionObjects::SceneObjectMap& DtConnectionObjects::sceneObjects() const
{
return mySceneObjectMap;
}
// Find the element id given a display name
DtElementID DtConnectionObjects::findElementID( const std::string& displayName ) const
{
DisplayNameToElementIdMap::const_iterator iter = myDisplayNameToElementIdMap.find( displayName );
if ( iter != myDisplayNameToElementIdMap.end() )
{
return iter->second;
}
return (DtElementID)0;
}
// Get the display name from an element id
std::string DtConnectionObjects::findDisplayName( DtElementID elementID ) const
{
ElementIdToDisplayNameMap::const_iterator iter = myElementIdToDisplayNameMap.find( elementID );
if ( iter != myElementIdToDisplayNameMap.end() )
{
return iter->second;
}
return "";
}
// Get the object id from an element id
std::string DtConnectionObjects::findObjectId( DtElementID elementID ) const
{
DtElementEntry* entry = myDe.dataBank().elementData().findElement( elementID );
if ( entry )
{
dynamic_cast<const DtElementAttributeConnectionObjectID*>(
entry->findAttribute( DtElementAttributes::ConnectionObjectID ) );
if ( objectIdAttr )
{
return objectIdAttr->value();
}
}
return "";
}
// Get the object type from an element id
std::string DtConnectionObjects::findObjectType( DtElementID elementID ) const
{
DtElementEntry* entry = myDe.dataBank().elementData().findElement( elementID );
if ( entry )
{
entry->findAttribute( DtElementAttributes::ConnectionObjectType ) );
if ( objectTypeAttr )
{
return objectTypeAttr->value();
}
}
return "";
}
// Note that DtSceneObject has an elementID method; so given a DtSceneObject,
// you can also look up the display name (which, when using DIS or HLA/RPR is
// the marking text
DtSceneObject* DtConnectionObjects::findSceneObject(DtElementID elementId ) const
{
SceneObjectMap::const_iterator iter = mySceneObjectMap.find( elementId );
if ( iter != mySceneObjectMap.end() )
{
return iter->second;
}
return 0;
}
void DtConnectionObjects::slot_sceneObjectToBeDeleted( const DtUniqueID& sceneObjId )
{
DtSceneObject* deletingObject = sceneObjectFromSceneObjectId( sceneObjId );
if ( deletingObject )
{
deletingObject->signal_sceneObjectToBeDeleted.disconnect(boost::bind(
&DtConnectionObjects::slot_sceneObjectToBeDeleted, this, _1 ) );
DtElementID elementId = deletingObject->elementID();
mySceneObjectMap[elementId] = 0;
}
}
void DtConnectionObjects::slot_elementsReadyToProcess(const DtElementData::ElementIdList& elements)
{
DtElementData::ElementIdList::const_iterator curIter = elements.begin();
DtElementData::ElementIdList::const_iterator endIter = elements.end();
for ( ; curIter != endIter; ++curIter )
{
DtElementEntry* entry = myDe.dataBank().elementData().findElement( *curIter );
if ( entry )
{
switch (entry->type() )
{
case DtElementEntry::Entity:
case DtElementEntry::Aggregate:
// All tactical graphics are either graphic shape or graphic point
case DtElementEntry::GraphicShape:
case DtElementEntry::GraphicPoint:
{
const DtElementAttributeDisplayName* displayNameAttr =
dynamic_cast<const DtElementAttributeDisplayName*>(
entry->findAttribute( DtElementAttributes::DisplayName ) );
if ( displayNameAttr )
{
std::string displayName = displayNameAttr->value();
// add entry to display name to element id map
DisplayNameToElementIdMap::iterator dnIter = myDisplayNameToElementIdMap.find( displayName );
if ( dnIter != myDisplayNameToElementIdMap.end() )
{
myDisplayNameToElementIdMap.erase( dnIter );
}
myDisplayNameToElementIdMap[displayName] = entry->elementID();
// add entry to element id to display name map
ElementIdToDisplayNameMap::iterator eiIter = myElementIdToDisplayNameMap.find( entry->elementID() );
if ( eiIter != myElementIdToDisplayNameMap.end() )
{
myElementIdToDisplayNameMap.erase( eiIter );
}
myElementIdToDisplayNameMap[entry->elementID()] = displayName;
}
DtSceneObject* sceneObject = sceneObjectFromElementId(
entry->elementID(), 0 );
if ( sceneObject )
{
// add entry to element id to scene object map
SceneObjectMap::iterator soIter = mySceneObjectMap.find( entry->elementID() );
if ( soIter != mySceneObjectMap.end() )
{
DtSceneObject* existingSceneObj = soIter->second;
if ( existingSceneObj )
{
existingSceneObj->signal_sceneObjectToBeDeleted.disconnect(boost::bind(
&DtConnectionObjects::slot_sceneObjectToBeDeleted, this, _1 ) );
}
mySceneObjectMap.erase( soIter );
}
mySceneObjectMap[entry->elementID()] = sceneObject;
sceneObject->signal_sceneObjectToBeDeleted.connect( boost::bind(
&DtConnectionObjects::slot_sceneObjectToBeDeleted, this, _1 ) );
}
signal_entityAdded( entry->elementID() );
}
break;
default:
break;
}
}
}
}
void DtConnectionObjects::slot_elementsRemoved( const DtElementData::ElementIdList& elements )
{
DtElementData::ElementIdList::const_iterator curIter = elements.begin();
DtElementData::ElementIdList::const_iterator endIter = elements.end();
for ( ; curIter != endIter; ++curIter )
{
DtElementEntry* entry = myDe.dataBank().elementData().findElement(*curIter);
if ( entry )
{
if ( entry->type() == DtElementEntry::Entity || entry->type() == DtElementEntry::Aggregate )
{
// signal before actually removing the entries from the maps so the
// maps are still usable to receivers of the signal
signal_entityRemoved( *curIter );
ElementIdToDisplayNameMap::const_iterator eiIter = myElementIdToDisplayNameMap.find( *curIter );
if ( eiIter != myElementIdToDisplayNameMap.end() )
{
DisplayNameToElementIdMap::const_iterator dnIter = myDisplayNameToElementIdMap.find( eiIter->second );
if ( dnIter != myDisplayNameToElementIdMap.end() )
{
myDisplayNameToElementIdMap.erase( dnIter );
}
myElementIdToDisplayNameMap.erase( eiIter );
}
SceneObjectMap::const_iterator soIter = mySceneObjectMap.find( *curIter );
if ( soIter != mySceneObjectMap.end() )
{
DtSceneObject* existingSceneObj = soIter->second;
if ( existingSceneObj )
{
existingSceneObj->signal_sceneObjectToBeDeleted.disconnect(boost::bind(
&DtConnectionObjects::slot_sceneObjectToBeDeleted, this, _1 ) );
}
mySceneObjectMap.erase( soIter );
}
}
}
}
}
}

DtConnectionObjects.h

/*****************************************************************************
* Copyright (c) 2015 MAK Technologies, Inc.
* All rights reserved.
*****************************************************************************/
#pragma once
#include <boost/unordered_map.hpp>
#include <string>
namespace makVrv
{
class DtDe;
class DtSceneObject;
class DtConnectionObjects
{
public:
typedef boost::unordered_map< std::string, DtElementID > DisplayNameToElementIdMap;
typedef boost::unordered_map< DtElementID, std::string > ElementIdToDisplayNameMap;
typedef boost::unordered_map< DtElementID, DtSceneObject* > SceneObjectMap;
DtConnectionObjects( DtDe& de );
// A useful utility
DtSceneObject* sceneObjectFromElementId( DtElementID elementId, int modelSet );
DtSceneObject* sceneObjectFromSceneObjectId( DtUniqueID sceneObjId );
// Iterating through this list, iterator::first will provide all the display names;
// iterator::second, all the elementIDs
// Iterating through this list, iterator::first will provide all the scene objects;
// iterator::second, all the elementIDs
// Find the element id given a display name
DtElementID findElementID( const std::string& displayName ) const;
// Get the display name from an element id
// Get the object id from an element id
std::string findObjectId( DtElementID elementID ) const;
// Get the object type from an element id
// Note that DtSceneObject has an elementID method; so given a DtSceneObject,
// you can also look up the display name (which, when using DIS or HLA/RPR is
// the marking text
DtSceneObject* findSceneObject(DtElementID elementId ) const;
boost::signal< void (DtElementID entity ) > signal_entityAdded;
boost::signal< void (DtElementID entity ) > signal_entityRemoved;
protected:
void slot_sceneObjectToBeDeleted( const DtUniqueID& sceneObjId );
protected:
DtDe& myDe;
typedef std::vector<DtElementEntry*> EntityElementEntryList;
};
}

DtConnectionObjectsDriver.cxx

/*****************************************************************************
* Copyright (c) 2015 MAK Technologies, Inc.
* All rights reserved.
*****************************************************************************/
#include <vrvCore/DtDe.h>
#include <boost/unordered_map.hpp>
#include <matrix/vlVector.h>
#include <iostream>
// Use the VR-Vantage namespace.
// All classes in VR-Vantage are in this namespace.
namespace makVrv
{
//
// Simple example of using the DtVantageEntityList
//
: makVrv::DtDriver( am, "DtConnectionObjectsDriver" )
, myConnectionObjects( new DtConnectionObjects( am.de() ) )
{
}
DtConnectionObjectsDriver::~DtConnectionObjectsDriver()
{
DtConnectionObjectsDriver::onStop();
delete myConnectionObjects;
myConnectionObjects = 0;
}
const std::string& DtConnectionObjectsDriver::className() const
{
static std::string name = "DtConnectionObjectsDriver";
return name;
}
bool DtConnectionObjectsDriver::onStart()
{
myConnectionObjects->signal_entityAdded.connect(
boost::bind( &DtConnectionObjectsDriver::slot_entityAdded, this, _1 ) );
myConnectionObjects->signal_entityRemoved.connect(
boost::bind( &DtConnectionObjectsDriver::slot_entityRemoved, this, _1 ) );
return true;
}
bool DtConnectionObjectsDriver::onStop()
{
myConnectionObjects->signal_entityAdded.disconnect(
boost::bind( &DtConnectionObjectsDriver::slot_entityAdded, this, _1 ) );
myConnectionObjects->signal_entityRemoved.disconnect(
boost::bind( &DtConnectionObjectsDriver::slot_entityRemoved, this, _1 ) );
return true;
}
bool DtConnectionObjectsDriver::onTick()
{
// This is NOT the right place to do something with the other entity positions,
// because they haven't been dead-reckoned yet. Connect to the
// de.renderer().signal_postUpdate and do anything that depends on an entity's
// position there (or install your own tickable, which is ticked during update,
// force an update on the scene object desired and then use its position/
// orientation).
return true;
}
void DtConnectionObjectsDriver::slot_entityAdded( DtElementID entity )
{
std::string displayName = myConnectionObjects->findDisplayName( entity );
std::string objectId = myConnectionObjects->findObjectId( entity );
std::string objectType = myConnectionObjects->findObjectType( entity );
std::cout
<< "Added " << displayName << std::endl
<< " ID " << objectId << std::endl
<< " Type " << objectType << std::endl;
// Schedule the printing out of this entity's current position in postUpdate, AFTER
// the scene object has been dead reckoned
//myAgentManager.de().renderer().signal_postUpdate.connect(
// boost::bind( &DtConnectionObjectsDriver::slot_postUpdate, this, entity ) );
}
void DtConnectionObjectsDriver::slot_entityRemoved( DtElementID entity )
{
// disconnect this entity from the postUpdate calls
//myAgentManager.de().renderer().signal_postUpdate.disconnect(
// boost::bind( &DtConnectionObjectsDriver::slot_postUpdate, this, entity ) );
std::string displayName = myConnectionObjects->findDisplayName( entity );
// At this point, you might want to insert this information into a class that can look up
// everything else by marking text, by element ID, etc...
std::cout
<< "Removed "
<< displayName
<< std::endl;
}
void DtConnectionObjectsDriver::slot_postUpdate( DtElementID entity )
{
DtSceneObject* sceneObject = myConnectionObjects->findSceneObject( entity );
std::string displayName = myConnectionObjects->findDisplayName( entity );
if ( sceneObject )
{
// Use the scene object to get dead-reckoned positions and orientations
DtVector position;
sceneObject->getPosition(0, position );
std::cout
<< displayName << " Position: "
<< position[0] << " " << position[1] << " " << position[2]
<< std::endl;
}
}
}


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