VR-Forces 4.8 Class Documentation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
exampleDisplayUnits

Table of Contents

Overview

The purpose of this example is to show how to use the Display Unit Manager to display an object's position, with appropriate labels, using the current Display Units settings. The example creates a plugin that displays a dialog with a drop down box that allows the user to chose from any of the elements currently selected in a scene, and displays the name, type, and position of the currently chosen element.

Expected Result

exampleDisplayUnits2.png
Display Unit example Result

Example details

The example also shows how to

Plugin Initialization

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

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

It then makes sure the vrvCoreQt plugin is initialized, as it depends on it (and since vrvCoreQt also calls DT_DE_INIT_ONCE, this call will do nothing if that plugin has already been initialized).

The plugin then registers a creator for the dialog page it will display (defined in ElementInspectorPage.cxx) with the DtQtPageAssembler.

DtQtPageAssembler::instance(de).registerPageCreator(new ElementInspectorPageCreator(de));

Finally, it defines how that dialog should appear in the GUI by adding a path to it in the masterModePageConfiguration.

if(igApp)
{
"ElementPanel",DtUnicode::fromAscii("Example Element Panel"),
DtPageConfiguration::FloatRight,true,"ElementInspectorPage",
false, true, true);
makVrv::DtPagePath::collection("ElementPanel").page("ElementInspectorPage"));
}

Element Inspector Page

The ElementInspectorPage dialog maintains a list box that contains all the currently selected elements. For access to this information, it needs to connect to a signal from the DtSelectionManager. Because the DtSelectionManager is created by the Display Engine, it's important to ensure that the connection is done after the Display Engine is fully initialized. One way the VR-Vantage toolkit enables this is through the DtDeObserver class. By inheriting from this class and overriding its slot_activate and slot_deactivate methods, the dialog can know when it is safe to connect (and needs to disconnect) from display engine managed signals creators.

The ElementInspectorPage declaration shows this inheritance.

class ElementInspectorPage : public DtPage, public DtDeObserver

In slot_activate, the ElementInspectorPage connects to the DtSelectionManager's selectionChanged signal.

void ElementInspectorPage::slot_activate(DtDe* de)
{
mySignals += DtSelectionManager::instance(myDe).signal_currentSelectionChanged.connect(
boost::bind(&ElementInspectorPage::selectionChanged,this,_1,_2,_3,_4));
}

It disconnects from the signal in slot_deactivate.

void ElementInspectorPage::slot_deactivate(DtDe* de)
{
// Display Engine is going away (so the selection manager is as well)
// Disconnect from its signal(s)
mySignals.disconnectSignals();
}

The ElementInspectorPage also needs to periodically update itself irrespective of any selection changes, since it displays the position of a selected element, that may be moving. However, it only needs to do this if it is actually displayed. Because it derives from DtPage, it can override DtPage's activate and deactivate methods to know when it is being displayed, and start and stop its refresh timer accordingly.

void ElementInspectorPage::activate()
{
myRefreshTimer->start();
}

void ElementInspectorPage::deactivate()
{
myRefreshTimer->stop();
}

Whenever a selection changes, or when the refresh timer expires, the dialog updates its information. The updateElementPosition method demonstrates the use of the DtDisplayUnitsSettingsManager to display the element's current position in the current coordinate system and with the current unit settings.

First, updateElementPosition gets a reference to an instance of the DtDisplayUnitsSettingsManager.

DtDisplayUnitsSettingsManager& mgr = DtDisplayUnitsSettingsManager::instance(myDe);

It queries the DtDisplayUnitsSettingsManager for the correct X, Y, and Z labels given the current display coordinate system and units, and sets the dialog's QLabel labels to those values.

DtUnicode xLabel,yLabel,zLabel;
mgr.converter().coordinateSystemLabels(xLabel,yLabel,zLabel);
myXLabel->setText(xLabel.toQString<QString>() + ":" );
myYLabel->setText(yLabel.toQString<QString>() + ":" );
myZLabel->setText(zLabel.toQString<QString>() + ":" );

Using the DtElementEntry passed into updateElementPosition, updateElementPosition gets the element's current position using its getPosition method.

DtVector position = getPosition(entry);

The position returned is in local (or database) coordinates; updateElementPosition coverts it to geocentric coordinates for use with the DtDisplayUnitsSettingsManager.

DtVector geocPosition;
myDe.sharedState().coordinateSystem().localToNetPos(position,geocPosition);

It then queries DtDisplayUnitManager with the geocentric position for properly format x, y, and z position strings, and sets its Qlabel value fields to the returned strings.

std::vector<std::string> strings =
mgr.converter().convertPositionToStringList(geocPosition);
if(strings.size() > 0)
{
myXValue->setText(QString::fromStdString(strings[0]));
}
if(strings.size() > 1)
{
myYValue->setText(QString::fromStdString(strings[1]));
}
if(strings.size() > 2)
{
myZValue->setText(QString::fromStdString(strings[2]));
}

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/exampleDisplayUnits_stealth.bat (on Windows) or ./bin64/exampleDisplayUnits_stealth.sh (on Linux). Load Makland terrain, from the menu "Settings->Connections...", connect to the localDIS. Then open MakLoggerDIS and load makland2016-DIS.lgr (make sure its connected with the local DIS also) and hit play. In Vantage Zoom on an entity and select it. You will see the entity information display in the popup that is created by this example.

For more information about running examples, please see Running Applications and Examples.

Example Source Files


ElementInspectorPage.h

/******************************************************************************
** Copyright (c) 2019 MAK Technologies, Inc.
** All rights reserved.
******************************************************************************/
#pragma once
#include <matrix/vlVector.h>
class QGridLayout;
class QLabel;
class QComboBox;
class QTimer;
namespace makVrv
{
class DtElementEntry;
namespace vrvExampleDisplayUnitsPlugin
{
class ElementInspectorPage : public DtPage, public DtDeObserver
{
Q_OBJECT;
public:
ElementInspectorPage(DtDe& de,QWidget* parent = 0, Qt::WindowFlags f = 0);
virtual QIcon icon();
virtual QString title();
virtual const std::string& pageClassName() const;
static const std::string& thePageClassName();
protected slots:
void onCurrentElementIdChanged(int index);
protected:
void setupGui();
virtual void activate();
virtual void deactivate();
virtual void slot_activate(DtDe* de);
virtual void slot_deactivate(DtDe* de);
const DtSelectionManager::IdSet& deselected,
void updateElementParameters(DtElementEntry* entry);
void updateElementPosition( DtElementEntry* entry );
void updateElementType( DtElementEntry* entry ) ;
DtVector getPosition( DtElementEntry* entry );
protected:
DtSignalConnectionManager mySignals;
QGridLayout* myMainLayout;
QTimer* myRefreshTimer;
};
typedef DtPageCreatorTemplate<ElementInspectorPage> ElementInspectorPageCreator;
}
}

ElementInspectorPage.cxx

/******************************************************************************
** Copyright (c) 2019 MAK Technologies, Inc.
** All rights reserved.
******************************************************************************/
#include <vrvCore/DtDe.h>
#include <QtWidgets/QLabel>
#include <QtWidgets/QGridLayout>
#include <QtWidgets/QComboBox>
#include <QtCore/QTimer>
#include <boost/bind.hpp>
using namespace makVrv;
using namespace vrvExampleDisplayUnitsPlugin;
ElementInspectorPage::ElementInspectorPage(DtDe& de,QWidget* parent, Qt::WindowFlags f)
: DtPage(de,parent,f)
, DtDeObserver()
{
// This sets us up to have our slot_activate() and slot_deactivate() methods
// called when the display engine is init'ed and uninit'ed
bind( de );
//Create and layout the widgets.
setupGui();
}
ElementInspectorPage::~ElementInspectorPage()
{
}
QIcon ElementInspectorPage::icon()
{
return QIcon();
}
QString ElementInspectorPage::title()
{
return tr("Element Inspector");
}
const std::string& ElementInspectorPage::pageClassName() const
{
return thePageClassName();
}
const std::string& ElementInspectorPage::thePageClassName()
{
static std::string theClassName("ElementInspectorPage");
return theClassName;
}
void ElementInspectorPage::activate()
{
myRefreshTimer->start();
}
void ElementInspectorPage::deactivate()
{
myRefreshTimer->stop();
}
void ElementInspectorPage::slot_activate(DtDe* de)
{
mySignals += DtSelectionManager::instance(myDe).signal_currentSelectionChanged.connect(
boost::bind(&ElementInspectorPage::selectionChanged,this,_1,_2,_3,_4));
}
void ElementInspectorPage::slot_deactivate(DtDe* de)
{
// Display Engine is going away (so the selection manager is as well)
// Disconnect from its signal(s)
mySignals.disconnectSignals();
}
void ElementInspectorPage::selectionChanged(const DtSelectionManager::IdSet& selected,
const DtSelectionManager::IdSet& deselected,
{
// For each selected id, add it to the combo box.
DtSelectionManager::IdSet::const_iterator i = selected.begin();
DtSelectionManager::IdSet::const_iterator e = selected.end();
for(; i != e;++i)
{
QString nameQStr = tr("Unnamed");
std::string nameStr;
if (myDe.dataBank().elementData().attributeManager().getElementDisplayName(*i, nameStr))
{
nameQStr = QString::fromStdString(nameStr);
}
myIdBox->addItem(nameQStr, QVariant(*i) );
}
// For each deselected id, find in in the combo box and remove it.
i = deselected.begin();
e = deselected.end();
for(; i != e;++i)
{
int index = myIdBox->findData( QVariant( *i ) );
if ( index != -1 )
{
myIdBox->removeItem(index);
}
}
}
void ElementInspectorPage::setupGui()
{
int row = 0;
myMainLayout = new QGridLayout(this);
myMainLayout->setAlignment(Qt::AlignTop);
myIdLabel = new QLabel(tr("Elements Selected:"),this);
myMainLayout->addWidget(myIdLabel,row,0);
myIdBox = new QComboBox(this);
QObject::connect(myIdBox,SIGNAL(currentIndexChanged(int)),SLOT(onCurrentElementIdChanged(int)));
myMainLayout->addWidget(myIdBox,row,1);
++row;
myTypeLabel = new QLabel(tr("Element Type:"),this);
myMainLayout->addWidget(myTypeLabel,row,0);
myTypeValue = new QLabel(tr(""),this);
myMainLayout->addWidget(myTypeValue,row,1);
++row;
myXLabel = new QLabel(this);
myMainLayout->addWidget(myXLabel,row,0);
myXValue = new QLabel(tr(""),this);
myMainLayout->addWidget(myXValue,row,1);
++row;
myYLabel = new QLabel(this);
myMainLayout->addWidget(myYLabel,row,0);
myYValue = new QLabel(tr(""),this);
myMainLayout->addWidget(myYValue,row,1);
++row;
myZLabel = new QLabel(this);
myMainLayout->addWidget(myZLabel,row,0);
myZValue = new QLabel(tr(""),this);
myMainLayout->addWidget(myZValue,row,1);
myRefreshTimer = new QTimer(this);
QObject::connect(myRefreshTimer,SIGNAL(timeout()),SLOT(onRefreshElementDisplay()));
myRefreshTimer->setInterval(500);
myRefreshTimer->stop();
}
void ElementInspectorPage::onCurrentElementIdChanged(int index)
{
if(index == -1)
{
updateElementParameters(0);
return;
}
//Get the unique id in the combo box.
DtUniqueID id = myIdBox->itemData(index).toULongLong();
//Find the element.
DtElementEntry* entry = myDe.dataBank().elementData().findElement(id);
//Update it's parameters, supports if the entry is NULL.
updateElementParameters(entry);
}
{
int index = myIdBox->currentIndex();
if( index == -1) return;
if(myIdBox->currentText() == QString()) return;
//Get the current element id.
bool ok = false;
DtUniqueID id = myIdBox->itemData(index).toULongLong(&ok);
if(!ok) return;
//Find the element.
//Update it's parameters, supports if the entry is NULL.
}
{
}
{
//Update the labels to based on the current display units settings.
DtUnicode xLabel,yLabel,zLabel;
mgr.converter().coordinateSystemLabels(xLabel,yLabel,zLabel);
myXLabel->setText(xLabel.toQString<QString>() + ":" );
myYLabel->setText(yLabel.toQString<QString>() + ":" );
myZLabel->setText(zLabel.toQString<QString>() + ":" );
if(entry)
{
//Get the position of the entry.
DtVector position = getPosition(entry);
//Get the position in geocentric.
DtVector geocPosition;
myDe.sharedState().coordinateSystem().localToNetPos(position,geocPosition);
//Get the position as it should be displayed.
std::vector<std::string> strings =
if(strings.size() > 0)
{
myXValue->setText(QString::fromStdString(strings[0]));
}
if(strings.size() > 1)
{
myYValue->setText(QString::fromStdString(strings[1]));
}
if(strings.size() > 2)
{
myZValue->setText(QString::fromStdString(strings[2]));
}
}
else
{
myXValue->clear();
myYValue->clear();
myZValue->clear();
}
}
{
if(entry)
{
QString typeStr;
switch(entry->type())
{
typeStr = tr("Entity");
break;
typeStr = tr("Aggregate");
break;
typeStr = tr("Prop");
break;
typeStr = tr("Observer");
break;
typeStr = tr("Graphic Point");
break;
typeStr = tr("Graphic Shape");
break;
typeStr = tr("Graphic Vertex");
break;
typeStr = tr("Remote Graphic");
break;
typeStr = tr("Intervisibility Line");
break;
typeStr = tr("Terrain Patch");
break;
typeStr = tr("Feature");
break;
default:
typeStr = tr("Unknown");
break;
}
myTypeValue->setText(typeStr);
}
else
{
}
}
{
if(!entry)
{
return DtVector::zero();
}
// Not everything has a scene object (and not everything has a position, such as
// a terrain patch or an intervisibility line). One example of something that
// does have a position but is not a scene object is an observer. Handle that first
if ( entry->type() == DtElementEntry::Observer )
{
std::string observerName;
{
DtObserver* observer = myDe.driverManager().inputDriver().findObserverByName( observerName );
{
if ( observer )
{
return observer->location();
}
return DtVector::zero();
}
}
return DtVector::zero();
}
//Find the first model set which is realized.
int modelSet = -1;
{
DtModelSetRealizationManager::ModelSetRealizations::const_iterator i =
DtModelSetRealizationManager::ModelSetRealizations::const_iterator e =
for ( ; i != e;++i)
{
if(i->second)
{
modelSet = i->first;
break;
}
}
}
//Find the scene objects for the element.
sceneObjects,modelSet);
if(sceneObjects.size() == 0)
{
return DtVector::zero();
}
//Find the resolver to get the scene object.
myDe.agentManager().findUpdater( sceneObjects.front() );
if( !resolver )
{
return DtVector::zero();
}
DtSceneObject* sceneObject =
resolver->castObjectTypeFromUpdater<DtSceneObject>( "DtSceneObject" );
if(!sceneObject)
{
return DtVector::zero();
}
//Get the position of the scene object.
DtVector position;
sceneObject->getPosition(0,position);
return position;
}

exampleDisplayUnitsPluginInit.cxx

/******************************************************************************
** Copyright (c) 2019 MAK Technologies, Inc.
** All rights reserved.
******************************************************************************/
#include <vrvCore/DtDe.h>
namespace makVrv
{
namespace vrvExampleDisplayUnitsPlugin
{
void init(DtDe& de)
{
// First make sure that the vrvCoreQt module is init'ed.
// Add the Example Page to the Example Dialog
//Add example menu and example menu settings item.
if(igApp)
{
"ElementPanel",DtUnicode::fromAscii("Example Element Panel"),
DtPageConfiguration::FloatRight,true,"ElementInspectorPage",
false, true, true);
makVrv::DtPagePath::collection("ElementPanel").page("ElementInspectorPage"));
}
}
}
}
{
return true;
}

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


Document ID: Generated on Thu Aug 27 10:56:05 EDT 2020 from SVN revision 217100
Copyright © 2005-2020 MAK Technologies. All Rights Reserved (www.mak.com)