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

Table of Contents

Overview

This example demonstrates how to add tactical graphics to the scene.

Expected Result

exampleTacticalGraphics1.png
Tactical Graphics Stealth Result
exampleTacticalGraphics2.png
Tactical Graphics PVD Result. Zoom in to see labels.

Example details

The example creates a DtExampleTacticalGraphicsDriver for creating line and area symbols that will be displayed on the Ground DB II database.

The driver creates the Tacticl Graphics by waiting for the first application tick, then creating appropriate 2D or 3D line elements according to the model set realized.

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

Example Source Files


DtExampleTacticalGraphicsDriver.h

/*****************************************************************************
* Copyright (c) 2023 MAK Technologies, Inc.
* All rights reserved.
*****************************************************************************/
#pragma once
#include <matrix/vlVector.h>
namespace makVrv
{
class DtTacticalGraphicOverlay;
class DtTacticalGraphicStateListener;
class DtTacticalGraphicElement;
class DtShapeTacticalGraphicElement;
class DtBaseConnection;
class DtEntityStateListener;
class DtEntityElement;
namespace exampleTacticalGraphics
{
class DT_DLL_EXAMPLESTACTICALGRAPHICS DtExampleTacticalGraphicsDriver
{
public:
DtExampleTacticalGraphicsDriver( makVrv::DtAgentManager& am );
virtual ~DtExampleTacticalGraphicsDriver();
virtual const std::string& className() const;
virtual bool onStart();
virtual bool onStop();
virtual bool onTick();
virtual void createSimpleLine();
virtual void createAirAxisLine();
virtual void createLineWithArrow();
virtual void createFortifiedLine();
virtual void createSimpleArea();
virtual void createFortifiedArea();
virtual void createPatternFilledArea();
virtual void createSimpleEntity();
virtual void createOverlays();
virtual void slot_tacticalGraphicVisibilityChanged(
const DtUniqueID& id, bool flag );
virtual DtTacticalGraphicStateListener* createTacticalGraphicElement( DtElementEntry::ElementType type,
std::string name, std::string elementDefinitionName, std::string overlyName );
virtual DtEntityStateListener* createEntityElement(
std::string name, std::string elementDefinitionName, std::string overlyName );
protected:
virtual void slot_displayEngineAdded( const makVrv::DtDeRecord& igRecord );
protected:
using TacticalGraphicPair = std::pair< DtTacticalGraphicStateListener*, DtTacticalGraphicElement* >;
std::vector< TacticalGraphicPair > myTacticalGraphics;
using EntityPair = std::pair< DtEntityStateListener*, DtEntityElement* >;
std::vector< EntityPair > myEntities;
bool myCreateElements;
DtBaseConnection* myBaseConnection;
vrvSignalsLib::connection myVisibilityChangedConnection;
};
}
}

DtExampleTacticalGraphicsDriver.cxx

/*****************************************************************************
* Copyright (c) 2024 MAK Technologies, Inc.
* All rights reserved.
*****************************************************************************/
#include <vrvCore/DtDe.h>
// Includes to pass instances from De to Base connection
// Used to communicate with elements & visualizers
// Derived DtTacticalGraphicElement that has vertices
// Required to create elements
#include <vrvCore/DtSceneObjectAgent.hpp>
#include <matrix/vlVector.h>
namespace makVrv
{
namespace exampleTacticalGraphics
{
static DtVector theSimpleLineVertices[] = {
DtVector(-20.0, 30.0, 40.0), DtVector(20.0, 90.0, 40.0),
DtVector(50.0, 50.0, 30.0), DtVector(100.0, 100.0, 30.0)
};
static DtVector theAirAxisVertices[] = {
DtVector(-300.0, -730.0, 700.0), DtVector(500.0, -300.0, 912.05),
DtVector(1400.0, -100.0, 825.62)
};
static DtVector theLineWithArrow[] = {
DtVector(-160.0,-260.0, 190.0), DtVector(0.0, -260.0, 190.0)
};
static DtVector theFortifiedLine[] = {
DtVector(500.0, 100.0, 20.0), DtVector(600.0,-100.0, 20.0),
DtVector(800.0,-100.0, 20.0)
};
static DtVector theSimpleAreaVertices[] = {
DtVector( 595.0, 320.0, 10.0 ), DtVector(560.0, 320.0, 10.0),
DtVector(560.0, 280.0, 10.0), DtVector(595.0, 280.0, 10.0)
};
static DtVector theFortifiedAreaVertices[] = {
DtVector(-160.0, 480.0, 90.0), DtVector(-65.0, 480.0, 90.0 ),
DtVector(-65.0, 550.0, 90.0), DtVector(-160.0, 550.0,90.0 )
};
static DtVector thePatternFilledAreaVertices[] = {
DtVector( -480.0, -820.0, 10.0 ), DtVector(-570.0,-820.0, 10.0),
DtVector(-570.0,-900.0, 10.0), DtVector(-480.0, -900.0, 10.0)
};
static bool is2D(DtModelSetId modelSet)
{
return ( modelSet == DtModelSetId::Icons2D);
}
static std::vector<DtVector> convertToPointVector(int numVertices, DtVector* pointVector)
{
int i;
std::vector<DtVector> points;
for (i = 0; i < numVertices; i++)
{
points.push_back(pointVector[i]);
}
return points;
}
: DtDriver( am, className() )
, myCreateElements(true)
, myBaseConnection( nullptr )
{
// intentional noop
}
DtExampleTacticalGraphicsDriver::~DtExampleTacticalGraphicsDriver()
{
// Don't call onStop here, driver manager calls it.
}
const std::string& DtExampleTacticalGraphicsDriver::className() const
{
static std::string name = "DtExampleTacticalGraphicsDriver";
return name;
}
bool DtExampleTacticalGraphicsDriver::onStart()
{
// Load Ground_DB II programatically.
DtScene& sceneDriver = myAgentManager.de().scene();
std::string groundDbPath = myAgentManager.de().dePathConfiguration().sharedDataPath();
groundDbPath += "/TerrainData/TerrainConfiguration/Ground_DB II.mtf";
sceneDriver.loadTerrain( groundDbPath );
DtTacticalGraphicOverlayManager& tgOverlayMgr =
DtTacticalGraphicOverlayManager::instance( myAgentManager.de() );
myVisibilityChangedConnection = tgOverlayMgr.signal_tacticalGraphicVisibilityChanged.connect( std::bind(
&DtExampleTacticalGraphicsDriver::slot_tacticalGraphicVisibilityChanged, this, std::placeholders::_1, std::placeholders::_2 ) );
// Create a base connection which is used during the creation of elements
myBaseConnection = new DtBaseConnection( DtSharedSettingsManager::instance( myAgentManager.de() ),
myAgentManager, myAgentManager.de().sharedState().coordinateSystem() );
// Copy across instances that are used during the creation of elements
// Copy symbol decoration factory from main thread.
DtSymbolDecorationFactory::copyInstance( *myBaseConnection, myAgentManager.de() );
// Copy visualizer factory from main thread.
DtStateVisualizerFactory::copyInstance( *myBaseConnection, myAgentManager.de() );
// Copy overlay groups from the main thread.
DtOverlayGroupManager::copyInstance( *myBaseConnection, myAgentManager.de() );
// Copy element definition types.
DtElementDefinitionTypeManager::copyInstance( *myBaseConnection, myAgentManager.de() );
// Copy the model sematics mapper.
DtModelSemanticsMapper::copyInstance( *myBaseConnection, myAgentManager.de() );
// Copy model definitions
DtModelDefinitionCollection::buildInstance( *myBaseConnection, myAgentManager.de() );
// Copy the element creators
DtElementFactory::copyInstance( *myBaseConnection, myAgentManager.de() );
// Initialize a Visualizer Creation Settings object.
DtVisualizerCreationSettingsManager::instance( myAgentManager.de() ).
initializeVisualizerCreationSettings( myBaseConnection->visualizerCreationSettings() );
return true;
}
bool DtExampleTacticalGraphicsDriver::onStop()
{
myVisibilityChangedConnection.disconnect();
auto iter = myTacticalGraphics.begin();
while( iter != myTacticalGraphics.end() )
{
if( iter->second)
{
delete iter->second;
iter->second = nullptr;
}
// Delete the listener after the element
if( iter->first )
{
delete iter->first;
iter->first = nullptr;
}
++iter;
}
auto entityIter = myEntities.begin();
while( entityIter != myEntities.end() )
{
if( entityIter->second )
{
delete entityIter->second;
entityIter->second = nullptr;
}
// Delete the listener after the element
if( entityIter->first )
{
delete entityIter->first;
entityIter->first = nullptr;
}
++entityIter;
}
// reset flag so facades get created when restarting the driver
myCreateElements = true;
// apply changes before stopping completely
if (myChanges.hasChanges())
{
myAgentManager.de().dataBank().elementData().applyChanges(myChanges);
myChanges.clear();
}
if( myBaseConnection )
{
// Element changes are reported the base connection
if( myBaseConnection->currentElementChanges().hasChanges() )
{
applyChangesAndDelete( myBaseConnection->takeElementChanges() );
}
delete myBaseConnection;
}
return true;
}
DtTacticalGraphicStateListener* DtExampleTacticalGraphicsDriver::createTacticalGraphicElement( DtElementEntry::ElementType type,
std::string name, std::string elementDefinitionName, std::string overlyName )
{
DtTacticalGraphicStateListener* tgListener = new DtTacticalGraphicStateListener( myAgentManager.createNewUniqueId(), myBaseConnection->settingsManager() );
if( !tgListener )
{
DtWarn << "DtExampleTacticalGraphicsDriver::createLineElements unable to create DtTacticalGraphicStateListener!" << std::endl;
}
tgListener->setName( name );
DtElement* temp = DtElementFactory::instance( myAgentManager.de() ).createElement(
type, *myBaseConnection, *tgListener, "" );
DtTacticalGraphicElement* tacticalGraphicElement = dynamic_cast<DtTacticalGraphicElement*>(temp);
if( !tacticalGraphicElement )
{
DtWarn << "DtExampleTacticalGraphicsDriver::createLineElements unable to create element!" << std::endl;
}
myTacticalGraphics.emplace_back( TacticalGraphicPair( tgListener, tacticalGraphicElement ) );
tacticalGraphicElement->setDriverType( "Tactical Graphics Driver" );
// Specify an element definition, see Settings->Visual Model Editor in the GUI
tacticalGraphicElement->setElementDefinition( DtUnicode::fromAscii( elementDefinitionName ) );
// Get all the currently enabled model sets
DtSharedModelSetSettings::ModelSetVisualizedMap sets;
{
DtReadSettingsLock<DtSharedModelSetSettings> modelSets( myBaseConnection->settingsManager() );
sets = modelSets->modelSetVisualizedMap();
}
// Visualize the element for all those enabled
tacticalGraphicElement->visualize( sets );
DtTacticalGraphicOverlay* overlay = DtTacticalGraphicOverlayManager::instance( myAgentManager.de() ).findOverlay( overlyName );
if( overlay && tacticalGraphicElement->findSceneObjectForModelSet( DtModelSetId::Icons2D ) )
{
overlay->addGraphic( tacticalGraphicElement->findSceneObjectForModelSet( DtModelSetId::Icons2D )->uniqueId() );
}
return tgListener;
}
void DtExampleTacticalGraphicsDriver::createSimpleLine()
{
DtTacticalGraphicStateListener* tgListener = createTacticalGraphicElement( DtElementEntry::GraphicShape, "Simple line", "Route", "Lines" );
// Use the listener to specify element attributes, these will be sent to all model sets
tgListener->setPixelLineWidth(4.0);
tgListener->setColor(1.0f, 0.0f, 0.0f, 0.777f);
tgListener->setFillStyle( vrvTacticalGraphicUtilities::FillStyle::SolidFill );
tgListener->setLocalVertexList( convertToPointVector( sizeof( theSimpleLineVertices ) / sizeof( DtVector ), &theSimpleLineVertices[0] ) );
tgListener->setEnvironmentalHatLinesEnabled( false, true );
}
void DtExampleTacticalGraphicsDriver::createAirAxisLine()
{
DtTacticalGraphicStateListener* tgListener = createTacticalGraphicElement( DtElementEntry::GraphicShape, "Air Axis", "Air Axis", "Lines" );
tgListener->setLocalVertexList( convertToPointVector( sizeof( theAirAxisVertices ) / sizeof( DtVector ), &theAirAxisVertices[0] ) );
tgListener->setLineStyle(vrvTacticalGraphicUtilities::LineStyle::AirAxis);
tgListener->setArrowSize(25.0);
}
void DtExampleTacticalGraphicsDriver::createLineWithArrow()
{
DtTacticalGraphicStateListener* tgListener = createTacticalGraphicElement( DtElementEntry::GraphicShape, "Line with arrow", "Linear Target", "Lines" );
tgListener->setLocalVertexList( convertToPointVector( sizeof( theLineWithArrow ) / sizeof( DtVector ), &theLineWithArrow[0] ) );
tgListener->setArrowHeadPlacement( vrvTacticalGraphicUtilities::ArrowHeadPlacement::LastSegmentOnly );
tgListener->setLineStyle( vrvTacticalGraphicUtilities::LineStyle::Plain );
tgListener->setArrowStyle( vrvTacticalGraphicUtilities::ArrowStyle::Simple );
tgListener->setProjected( false );
tgListener->setArrowSize( 25.0 );
}
void DtExampleTacticalGraphicsDriver::createFortifiedLine()
{
DtTacticalGraphicStateListener* tgListener = createTacticalGraphicElement( DtElementEntry::GraphicShape, "Fortified Line", "Fortified Line", "Lines" );
tgListener->setLocalVertexList( convertToPointVector( sizeof( theFortifiedLine ) / sizeof( DtVector ), &theFortifiedLine[0] ) );
tgListener->setColor(1.0f, 0.0f, 0.0f, 0.777f);
tgListener->setEnvironmentalHatLinesEnabled( false, true );
}
void DtExampleTacticalGraphicsDriver::createSimpleArea()
{
DtTacticalGraphicStateListener* tgListener = createTacticalGraphicElement( DtElementEntry::GraphicShape, "Simple Area", "Other Area", "Areas" );
tgListener->setClosedFigure(true);
tgListener->setPixelLineWidth( 4.0 );
tgListener->setColor( 0.0f, 1.0f, 0.0f, 0.777f );
tgListener->setLocalVertexList( convertToPointVector( sizeof( theSimpleAreaVertices ) / sizeof( DtVector ), &theSimpleAreaVertices[0] ) );
tgListener->setEnvironmentalHatLinesEnabled( false, true );
}
void DtExampleTacticalGraphicsDriver::createFortifiedArea()
{
DtTacticalGraphicStateListener* tgListener = createTacticalGraphicElement( DtElementEntry::GraphicShape, "Fortified Area", "Fortified Area", "Areas" );
tgListener->setClosedFigure(true);
tgListener->setColor( 0.0f, 1.0f, 0.0f, 0.777f );
tgListener->setLocalVertexList( convertToPointVector( sizeof( theFortifiedAreaVertices ) / sizeof( DtVector ), &theFortifiedAreaVertices[0] ) );
tgListener->setEnvironmentalHatLinesEnabled( false, true );
}
void DtExampleTacticalGraphicsDriver::createPatternFilledArea()
{
DtTacticalGraphicStateListener* tgListener = createTacticalGraphicElement( DtElementEntry::GraphicShape, "Filled Area", "Other Area", "Areas" );
tgListener->setClosedFigure(true);
tgListener->setFillStyle( vrvTacticalGraphicUtilities::FillStyle::HorizontalLines );
tgListener->setLocalVertexList( convertToPointVector( sizeof( thePatternFilledAreaVertices ) / sizeof( DtVector ), &thePatternFilledAreaVertices[0] ) );
tgListener->setEnvironmentalHatLinesEnabled( false, true );
}
void DtExampleTacticalGraphicsDriver::createSimpleEntity()
{
DtEntityStateListener* entityListener = createEntityElement( "FA-18 Hornet", "F/A-18 Hornet", "Symbols" );
entityListener->setForceId( 1 );
entityListener->setForceColor( 0.5f, 224.0f / 255.0f, 1.0f, 0.8f );
entityListener->setLocalLocation( DtVector( -300.0, -730.0, 750.0 ) );
}
void DtExampleTacticalGraphicsDriver::createOverlays()
{
DtTacticalGraphicOverlayManager::instance( myAgentManager.de() ).addOverlay( "Lines" );
DtTacticalGraphicOverlayManager::instance( myAgentManager.de() ).addOverlay( "Areas" );
DtTacticalGraphicOverlayManager::instance( myAgentManager.de() ).addOverlay( "Symbols" );
}
void DtExampleTacticalGraphicsDriver::slot_tacticalGraphicVisibilityChanged(
const DtUniqueID& id, bool flag )
{
auto iter = myTacticalGraphics.begin();
while( iter != myTacticalGraphics.end() )
{
if( iter->second && iter->second->elementID() == id)
{
iter->second->setVisible( flag );
return;
}
++iter;
}
auto entityIter = myEntities.begin();
while( entityIter != myEntities.end() )
{
if( entityIter->second && entityIter->second->elementID() == id )
{
iter->second->setVisible( flag );
return;
}
++entityIter;
}
}
DtEntityStateListener* DtExampleTacticalGraphicsDriver::createEntityElement( std::string name, std::string elementDefinitionName, std::string overlyName )
{
DtEntityStateListener* entityListener = new DtEntityStateListener( myAgentManager.createNewUniqueId(), myBaseConnection->settingsManager() );
if( !entityListener )
{
DtWarn << "DtExampleTacticalGraphicsDriver::createSimpleEntity() unable to create DtEntityStateListener!" << std::endl;
}
entityListener->setDisplayName( name );
DtElement* temp = DtElementFactory::instance( myAgentManager.de() ).createElement(
DtElementEntry::Entity, *myBaseConnection, *entityListener, "" );
DtEntityElement* entityElement = dynamic_cast<DtEntityElement*>(temp);
if( !entityElement )
{
DtWarn << "DtExampleTacticalGraphicsDriver::createLineElements unable to create element!" << std::endl;
}
myEntities.emplace_back( EntityPair( entityListener, entityElement ) );
entityElement->setDriverType( "Tactical Graphics Driver" );
// Specify an element definition, see Settings->Visual Model Editor in the GUI
entityElement->setElementDefinition( DtUnicode::fromAscii( elementDefinitionName ) );
// Get all the currently enabled model sets
DtSharedModelSetSettings::ModelSetVisualizedMap sets;
{
DtReadSettingsLock<DtSharedModelSetSettings> modelSets( myBaseConnection->settingsManager() );
sets = modelSets->modelSetVisualizedMap();
}
// Visualize the element for all those enabled
entityElement->visualize( sets );
DtTacticalGraphicOverlay* overlay = DtTacticalGraphicOverlayManager::instance( myAgentManager.de() ).findOverlay( overlyName );
if( overlay && entityElement->findSceneObjectForModelSet( DtModelSetId::Icons2D ) )
{
overlay->addGraphic( entityElement->findSceneObjectForModelSet( DtModelSetId::Icons2D )->uniqueId() );
}
return entityListener;
}
bool DtExampleTacticalGraphicsDriver::onTick()
{
if (myCreateElements)
{
myCreateElements = false;
createOverlays();
createSimpleLine();
createAirAxisLine();
createLineWithArrow();
createFortifiedLine();
createSimpleArea();
createFortifiedArea();
createPatternFilledArea();
createSimpleEntity();
// Element changes are reported to the base connection
// These changes are then passed to the display engine
if( myBaseConnection->currentElementChanges().hasChanges() )
{
applyChangesAndDelete( myBaseConnection->takeElementChanges() );
}
}
return true;
}
void DtExampleTacticalGraphicsDriver::slot_displayEngineAdded( const DtDeRecord& igRecord )
{
// When a new display engine is connected to our driver, the driver
// must be re-started in order to ensure the terrain and all symbols
// are properly loaded on all connected De's.
stop();
start();
}
}
}

exampleTacticalGraphics.h

/*****************************************************************************
* Copyright (c) 2019 MAK Technologies, Inc.
* All rights reserved.
*****************************************************************************/
#pragma once
// Plugin export macro.
#ifdef _WIN32
# ifdef EXAMPLETACTICALGRAHICS_EXPORTS
# define DT_DLL_EXAMPLESTACTICALGRAPHICS __declspec ( dllexport )
# else
# define DT_DLL_EXAMPLESTACTICALGRAPHICS __declspec ( dllimport )
# endif
#else
# define DT_DLL_EXAMPLESTACTICALGRAPHICS
#endif
// Declare & export the plugin initialization function (bool initDeModule(DtDe* de))
#define DT_DE_PLUGIN_EXPORT_MACRO DT_DLL_EXAMPLESTACTICALGRAPHICS
// Plugin initialization methods.

exampleTacticalGraphics.cxx

/*****************************************************************************
* Copyright (c) 2023 MAK Technologies, Inc.
* All rights reserved.
*****************************************************************************/
#include <vrvCore/DtDe.h>
// Use the VR-Vantage namespace.
// All classes in VR-Vantage are in this namespace.
using namespace makVrv;
using namespace makVrv::exampleTacticalGraphics;
static vrvSignalsLib::connection postInitializeConnection;
bool initDeModule( DtDe* de )
{
// Setup the plug-in.
init( *de );
return true;
}
void init( DtDe& de )
{
// Ensure that init only gets called once
// (not strictly necessary here, but this is good practice in general)
// Make sure that the vrvCoreQt and vrvOsgEarthQt module are init'ed.
// Don't show the startup dialog for selecting a terrain.
DtQtDeMainWindow& mainWindow = dynamic_cast<DtQtDeMainWindow&>(mw);
mainWindow.hideStartupDialog();
// We only want to create the driver if we are running in master mode.
if ( de.isInMasterMode() )
{
// The accessory 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 )
{
// Create DtExampleDriver.
// The driver is now owned by the display engine. Do not delete it.
de.driverManager().addDriver( driver );
// Start the driver, creating the agent.
de.driverManager().startDriver( driver );
}

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


Document ID: Generated on Wed Mar 27 22:49:11 EDT 2024 from SVN revision 264633
Copyright © 2005-2024 MAK Technologies. All Rights Reserved (www.mak.com)