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

Table of Contents

Overview

Create a simulated gimbaled camera and control an observer with it.

Expected Result

exampleGimbalPlugin.png
Gimbal Plugin Result

Example details

DtGimbalDriver looks for the plane element created by DtExampleDriver (or DtDriverExamplePlugin) and implements a gimbal attached to that plane at a specified offset. It shows how to use the DtGeoReference class to position and orient the gimbal using the plane's position and orientation; and how to find azimuth and elevation angles to a target in the gimbal's local coordinate system. It attaches the observer named "Observer 1" to the gimbal, and uses the azimuth and elevation angles determined to lock the observer onto the target location.

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

Example Source Files

DtGimbalDriver.h

/*****************************************************************************
* Copyright (c) 2019 MAK Technologies, Inc.
* All rights reserved.
*****************************************************************************/
#pragma once
#include <string>
namespace makVrv
{
class DtGeoReference;
class DtSceneObjectAgent;
class DtSceneObject;
}
class DtGeodeticCoord;
{
public:
virtual ~DtGimbalDriver();
virtual const std::string& className() const;
protected:
virtual bool onStart();
virtual bool onStop();
virtual bool onTick();
virtual void attachObserverToEntity( const std::string& entityName );
virtual void slot_displayEngineAdded( const makVrv::DtDeRecord& igRecord );
virtual bool initialize();
private:
protected:
makVrv::DtSceneObjectAgent* myGimbalSceneObjectAgent;
DtGeodeticCoord* myTargetLocation;
};

DtGimbalDriver.cxx

/*****************************************************************************
* Copyright (c) 2022 MAK Technologies, Inc.
* All rights reserved.
*****************************************************************************/
#include "DtGimbalDriver.h"
#include <vrvCore/DtDe.h>
#include <vrvCore/DtSceneObjectAgent.hpp>
#include <vlutil/vlUtil.h>
// Use the VR-Vantage namespace.
// All classes in VR-Vantage are in this namespace.
using namespace makVrv;
const double DtTargetLatitude = DtDeg2Rad( -0.0054 );
const double DtTargetLongitude = DtDeg2Rad( -0.0017 );
const double DtTargetAltitude = 25.00;
const double DtGimbalForwardOffset = 2.0;
const double DtGimbalDownOffset = 2.5;
const double DtGimbalRightOffset = 0.;
: makVrv::DtDriver( am, "DtGimbalDriver" )
, myPlaneGeoRef( 0 )
, myGimbalGeoRef( 0 )
, myGimbalSceneObjectAgent( 0 )
, myTargetLocation( 0 )
, myPlaneSceneObject( 0 )
, myGimbalId( 0 )
{
myTargetLocation = new DtGeodeticCoord( DtTargetLatitude, DtTargetLongitude, DtTargetAltitude,
myAgentManager.de().sharedState().coordinateSystem().referenceEllipsoid() );
mySignalConnections += DtDeSharedStateSignaler::instance( myAgentManager.de() )
.signal_coordinateSystemChanged.connect( boost::bind(
}
{
{
}
DtDELETE( myPlaneGeoRef );
DtDELETE( myGimbalGeoRef );
DtDELETE( myTargetLocation );
}
{
DtDELETE( myTargetLocation );
myTargetLocation = new DtGeodeticCoord( DtTargetLatitude, DtTargetLongitude, DtTargetAltitude,
}
const std::string& DtGimbalDriver::className() const
{
static std::string name = "DtGimbalDriver";
return name;
}
{
// look up the plane from exampleDriver (or exampleDriverPlugin)
// It has display name "Entity From Facade"
bool found = false;
// Iterate through all the elements
DtElementData::ElementEntryMap::const_iterator curIter = elemData.elements().begin();
DtElementData::ElementEntryMap::const_iterator endIter = elemData.elements().end();
for( ; curIter != endIter; ++curIter )
{
std::string entityName;
if (elemData.attributeManager().getElementDisplayName(curIter->first, entityName) &&
entityName == "UAV 1")
{
// Found it. Look up the scene object id used to visualize this element
// in the 3D model set. We can use that scene object to get the position
// and orientation of the plane
DtElementID planeElementId = curIter->first;
elemData.getSceneObjectIds(planeElementId,
sceneObjectIds, DtSceneObject::ModelSet_3D );
// getSceneObjectIds() can return multiple scene object ids if multiple model sets
// are specified. Since we only asked for the 3D model set scene object,
// sceneObjectIds.size() should be 1.
// It *should* be one, but because ExampleDriverPlugin DtExampleSimEngine::init
// adds a hatlinefacade to the element there are two scene objects on the element
if ( sceneObjectIds.size() == 2 )
{
DtAgentUpdateResolverInterface* updater = agentManager().findUpdater( sceneObjectIds.front() );
if(updater)
{
found = true;
}
}
}
}
// If we didn't find it, assume it hasn't been created yet. Return false, and we'll
// try again next tick
if (! found )
{
return false;
}
// We have the plane's scene object. Now we can create GeoReferences for the
// plane and the Gimbal
// We create a scene object (and associate it with an element) for the Gimbal so that
// our observer can be attached to it. When an observer is attached to an element in
// Mimic mode, it effectively uses that element's coordinate system; so attaching to
// this Gimbal gives us an observer in Gimbal coordinates. Note that no models are
// added to the scene object, so this element will be invisible (but if you had a 3D
// gimbal model you could create and add it here
myGimbalSceneObjectAgent = DtSceneObjectAgent::create( myAgentManager );
myGimbalSceneObjectAgent->setModelSet( DtObserverMode::ModelSet3dModels );
// Set up the element
myGimbalSceneObjectAgent->setElementID( myGimbalId );
// Give the element a name that we can use to attach to it
DtElementAttributeDriverType* driverType = new DtElementAttributeDriverType( "Gimbal Driver");
return true;
}
{
return true;
}
{
return true;
}
{
if ( myGimbalSceneObjectAgent == NULL )
{
if ( ! initialize() )
{
return true;
}
// The plane was found. Attach to it.
}
// Set up a GeoRef for the plane. We use this to find the Gimbal position
// and orientation for the Gimbal scene object (and Gimbal GeoRef)
DtVector planePosition;
DtTaitBryan planeOrientation;
// Drivers are ticked early in the frame. Entities are dead-reckoned later.
// So at this point, we only have the position and orientation of where the entity
// was last frame, not necessarily where it will be this frame. However, we can
// directly request that it update NOW rather than when all the other entities
// update.
if (updater)
{
{
}
}
// Now we can get the entity's position and orientation for this frame.
myPlaneSceneObject->getPosition( 0, planePosition );
myAgentManager.de().sharedState().coordinateSystem() ), planeOrientation );
// Find the position and orientation of the gimbal in geodetic coordinates, using
// the GeoRef placed above;
DtGeodeticCoord gimbalGeod;
DtTaitBryan gimbalOri;
DtVector( DtGimbalForwardOffset, DtGimbalRightOffset, DtGimbalDownOffset),
DtTaitBryan(0., 0., 0.),
gimbalGeod, gimbalOri );
// Set up a GeoRef for our Gimbal
myGimbalGeoRef->setLocationAndOrientation( gimbalGeod, gimbalOri );
// Position our gimbal object
myGimbalSceneObjectAgent->setPosition( 0, DtGeodeticToLocal( gimbalGeod,
myGimbalSceneObjectAgent->setTopographicOrientation( 0, gimbalOri );
// Get tower location in gimbal's topocentric system. (We don't need the tower's orientation)
DtVector targetTopo;
DtTaitBryan unused( 0., 0., 0. );
myGimbalGeoRef->geodeticToTopo( *myTargetLocation, unused, targetTopo, unused );
// find azimuth and elevation angles to our target
double azimuthAngle = -atan2( targetTopo[1], targetTopo[0] );
double xyPlaneDistance = sqrt( targetTopo[0] * targetTopo[0] + targetTopo[1] * targetTopo[1] );
double elevationAngle = DtDeg2Rad( 90. ) - atan2( xyPlaneDistance, -targetTopo[2] );
// Get the main observer
if ( observer )
{
// Set the observer's azimuth and elevation angle to keep the tower in view
observer->setAttachedOrientation( azimuthAngle, elevationAngle, 0. );
}
return true;
}
void DtGimbalDriver::attachObserverToEntity( const std::string& entityName )
{
DtObserver* observer = myAgentManager.de().
driverManager().inputDriver().findObserverByName( "Observer 1" );
if ( observer )
{
// Start by getting the existing observer state record for this observer.
// We can modify it and then set it back. We use the observer record
// mechanism because it will allow the observer to attach even if the
// plane hasn't been created yet (the observer will retry attaching when
// an observer record is used until the attach succeeds
observer->getRecord( observerState );
// Attach to the plane
std::set<std::string> displayNames;
displayNames.insert( entityName );
observerState.setAttachedToDisplayNames( displayNames );
// We want no offset
observerState.setObserverOffsetVector( 0., 0., 0. );
// Get the observer settings record associated with this observer state record
// so we can force the attach type to mimic
// Add the modified settings record back to the observer state record
observerState.setObserverSettingsRecord( settingsRec );
// Set a view magnification
observerState.setViewMagnification( 100. );
// ... and then add the observer state to the observer
observer->setFromRecord( observerState );
}
}
{
stop();
start();
}

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


Document ID: Generated on Thu Jun 1 17:58:13 EDT 2023 from SVN revision 255404
Copyright © 2005-2021 MAK Technologies. All Rights Reserved (www.mak.com)